1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 or later
5    * as published by the Free Software Foundation. This program is distributed
6    * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7    * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *      http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * © CrossWire Bible Society, 2015 - 2016
18   */
19  package org.crosswire.common.util;
20  
21  import java.util.AbstractCollection;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Comparator;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Set;
28  import java.util.TreeSet;
29  
30  /**
31   * Defines a List that maintains the uniqueness of elements
32   *
33   * @param <E> The type of the element in this ListSet.
34   * @see gnu.lgpl.License The GNU Lesser General Public License for details.
35   * @author DM Smith
36   */
37  public class ListSet<E> extends AbstractCollection<E> implements Set<E> {
38  
39      /**
40       * Constructs a new, empty list set.
41       */
42      public ListSet() {
43          this(null);
44      }
45  
46      /**
47       * Constructs a new, empty list set, sorted according to the specified
48       * comparator.  All elements inserted into the set must be <i>mutually
49       * comparable</i> by the specified comparator: {@code comparator.compare(e1,
50       * e2)} must not throw a {@code ClassCastException} for any elements
51       * {@code e1} and {@code e2} in the set.  If the user attempts to add
52       * an element to the set that violates this constraint, the
53       * {@code add} call will throw a {@code ClassCastException}.
54       *
55       * @param comparator the comparator that will be used to order this set.
56       *        If {@code null}, the {@linkplain Comparable natural
57       *        ordering} of the elements will be used.
58       */
59      public ListSet(Comparator<? super E> comparator) {
60          super();
61          list = new ArrayList();
62          set  = new TreeSet(comparator);
63      }
64  
65      @Override
66      public boolean contains(Object o) {
67          return set.contains(o);
68      }
69  
70      @Override
71      public boolean add(E e) {
72          boolean added = set.add(e);
73          if (added) {
74              list.add(e);
75          }
76          return added;
77      }
78  
79      @Override
80      public boolean remove(Object o) {
81          boolean removed = set.remove(o);
82          if (removed) {
83              list.remove(o);
84          }
85          return removed;
86      }
87  
88      public E remove(int index) {
89          E t = list.get(index);
90          remove(t);
91          return t;
92      }
93  
94      @Override
95      public boolean containsAll(Collection<?> c) {
96          return set.containsAll(c);
97      }
98  
99      @Override
100     public boolean retainAll(Collection<?> c) {
101         boolean removed = false;
102         Iterator<E> it = this.iterator();
103         while (it.hasNext()) {
104             E next = it.next();
105             if (!c.contains(next)) {
106                 it.remove();
107                 removed = true;
108             }
109         }
110         return removed;
111     }
112 
113     @Override
114     public int size() {
115         return list.size();
116     }
117 
118     @Override
119     public boolean isEmpty() {
120         return list.isEmpty();
121     }
122 
123     @Override
124     public void clear() {
125         set.clear();
126         list.clear();
127     }
128 
129     public E get(int index) {
130         return list.get(index);
131     }
132 
133     public E get(int index, E defaultValue) {
134         E value = list.get(index);
135         return value != null ? value : defaultValue;
136     }
137 
138     @Override
139     public Iterator<E> iterator() {
140         // Need to properly implement remove
141         return new Iterator<E>() {
142             public boolean hasNext() {
143                 return itr.hasNext();
144             }
145 
146             public E next() {
147                 E next = itr.next();
148                 current = next;
149                 return next;
150             }
151 
152             public void remove() {
153                 itr.remove();
154                 set.remove(current);
155                 current = null;
156             }
157 
158             private Iterator<E> itr = list.iterator();
159             private E current;
160         };
161     }
162 
163     @Override
164     public Object[] toArray() {
165         return list.toArray();
166     }
167 
168     @Override
169     public <T> T[] toArray(T[] a) {
170         return list.toArray(a);
171     }
172 
173     protected List<E> list;
174     protected Set<E> set;
175 }
176