blob: 189b97f8544a548e0ebdfc71235daad098faa604 [file] [log] [blame]
Stuart McCullochf3173222012-06-07 21:57:32 +00001package aQute.lib.collections;
2
3import java.util.*;
4
5/**
6 * An immutbale list that sorts objects by their natural order or through a
7 * comparator. It has convenient methods/constructors to create it from
Stuart McCulloch4482c702012-06-15 13:27:53 +00008 * collections and iterators. Why not maintain the lists in their sorted form?
9 * Well, TreeMaps are quite expensive ... I once profiled bnd and was shocked
10 * how much memory the Jar class took due to the TreeMaps. I could not easily
11 * change it unfortunately. The other reason is that Parameters uses a
12 * LinkedHashMap because the preferred order should be the declaration order.
13 * However, sometimes you need to sort the keys by name. Last, and most
14 * important reason, is that sometimes you do not know what collection you have
15 * or it is not available in a sort ordering (MultiMap for example) ... I found
16 * myself sorting these things over and over again and decided to just make an
17 * immutable SortedList that is easy to slice and dice
Stuart McCullochf3173222012-06-07 21:57:32 +000018 *
19 * @param <T>
20 */
Stuart McCulloch4482c702012-06-15 13:27:53 +000021@SuppressWarnings("unchecked")
22public class SortedList<T> implements SortedSet<T>, List<T> {
23 static SortedList< ? > empty = new SortedList<Object>();
Stuart McCullochf3173222012-06-07 21:57:32 +000024
25 final T[] list;
26 final int start;
27 final int end;
28 final Comparator<T> cmp;
Stuart McCulloch4482c702012-06-15 13:27:53 +000029 Class< ? > type;
Stuart McCullochf3173222012-06-07 21:57:32 +000030 static Comparator<Object> comparator = //
31
32 new Comparator<Object>() {
33 public int compare(Object o1, Object o2) {
34
35 if (o1 == o2)
36 return 0;
37
38 if (o1.equals(o2))
39 return 0;
40
41 return ((Comparable<Object>) o1).compareTo(o2);
42 }
43 };
44
45 class It implements ListIterator<T> {
46 int n;
47
Stuart McCulloch2b3253e2012-06-17 20:38:35 +000048 It(int n) {
Stuart McCullochf3173222012-06-07 21:57:32 +000049 this.n = n;
50 }
51
52 public boolean hasNext() {
53 return n < end;
54 }
55
56 public T next() throws NoSuchElementException {
57 if (!hasNext()) {
58 throw new NoSuchElementException("");
59 }
60 return list[n++];
61 }
62
63 public boolean hasPrevious() {
64 return n > start;
65 }
66
67 public T previous() {
68 return get(n - 1);
69 }
70
71 public int nextIndex() {
72 return (n + 1 - start);
73 }
74
75 public int previousIndex() {
76 return (n - 1) - start;
77 }
78
Stuart McCulloch4482c702012-06-15 13:27:53 +000079 @Deprecated
80 public void remove() {
Stuart McCullochf3173222012-06-07 21:57:32 +000081 throw new UnsupportedOperationException("Immutable");
82 }
83
Stuart McCulloch4482c702012-06-15 13:27:53 +000084 @Deprecated
85 public void set(T e) {
Stuart McCullochf3173222012-06-07 21:57:32 +000086 throw new UnsupportedOperationException("Immutable");
87 }
88
Stuart McCulloch4482c702012-06-15 13:27:53 +000089 @Deprecated
90 public void add(T e) {
Stuart McCullochf3173222012-06-07 21:57:32 +000091 throw new UnsupportedOperationException("Immutable");
92 }
93 }
94
Stuart McCulloch4482c702012-06-15 13:27:53 +000095 public SortedList(Collection< ? extends Comparable< ? >> x) {
Stuart McCullochf3173222012-06-07 21:57:32 +000096 this((Collection<T>) x, 0, x.size(), (Comparator<T>) comparator);
97 }
98
99 public SortedList(Collection<T> x, Comparator<T> cmp) {
100 this(x, 0, x.size(), cmp);
101 }
102
103 @SuppressWarnings("cast")
104 public SortedList(T... x) {
105 this((T[]) x.clone(), 0, x.length, (Comparator<T>) comparator);
106 }
107
108 @SuppressWarnings("cast")
109 public SortedList(Comparator<T> cmp, T... x) {
110 this((T[]) x.clone(), 0, x.length, cmp);
111 }
112
113 private SortedList(SortedList<T> other, int start, int end) {
114 this.list = other.list;
115 this.cmp = other.cmp;
116 this.start = start;
117 this.end = end;
118 }
119
120 public SortedList(T[] x, int start, int end, Comparator<T> comparator2) {
121 if (start > end) {
122 int tmp = start;
123 start = end;
124 end = tmp;
125 }
126 if (start < 0 || start >= x.length)
127 throw new IllegalArgumentException("Start is not in list");
128
129 if (end < 0 || end > x.length)
130 throw new IllegalArgumentException("End is not in list");
131
132 this.list = x.clone();
133 Arrays.sort(this.list, start, end, comparator2);
134 this.start = start;
135 this.end = end;
136 this.cmp = comparator2;
137 }
138
Stuart McCulloch4482c702012-06-15 13:27:53 +0000139 public SortedList(Collection< ? extends T> x, int start, int end, Comparator<T> cmp) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000140 if (start > end) {
141 int tmp = start;
142 start = end;
143 end = tmp;
144 }
145 if (start < 0 || start > x.size())
146 throw new IllegalArgumentException("Start is not in list");
147
148 if (end < 0 || end > x.size())
149 throw new IllegalArgumentException("End is not in list");
150
151 this.list = (T[]) x.toArray();
152 Arrays.sort(this.list, start, end, cmp);
153 this.start = start;
154 this.end = end;
155 this.cmp = cmp;
156 }
157
158 private SortedList() {
159 list = null;
160 start = 0;
161 end = 0;
162 cmp = null;
163 }
164
165 public int size() {
166 return end - start;
167 }
168
169 public boolean isEmpty() {
170 return start == end;
171 }
172
173 @SuppressWarnings("cast")
174 public boolean contains(Object o) {
175 assert type != null & type.isInstance(o);
176 return indexOf((T) o) >= 0;
177 }
178
179 public Iterator<T> iterator() {
180 return new It(start);
181 }
182
183 public Object[] toArray() {
184 return list.clone();
185 }
186
Stuart McCulloch4482c702012-06-15 13:27:53 +0000187 @SuppressWarnings("hiding")
188 public <T> T[] toArray(T[] a) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000189 if (a == null || a.length < list.length) {
190 return (T[]) list.clone();
191 }
192 System.arraycopy(list, 0, a, 0, list.length);
193 return a;
194 }
195
196 public boolean add(T e) {
197 throw new UnsupportedOperationException("Immutable");
198 }
199
200 public boolean remove(Object o) {
201 throw new UnsupportedOperationException("Immutable");
202 }
203
Stuart McCulloch4482c702012-06-15 13:27:53 +0000204 public boolean containsAll(Collection< ? > c) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000205 if (c.isEmpty())
206 return true;
207
208 if (isEmpty())
209 return false;
210
211 // TODO take advantage of sorted nature for this
212
213 for (Object el : c) {
214 if (!contains(el))
215 return false;
216 }
217 return false;
218 }
219
Stuart McCulloch4482c702012-06-15 13:27:53 +0000220 public boolean addAll(Collection< ? extends T> c) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000221 throw new UnsupportedOperationException("Immutable");
222 }
223
Stuart McCulloch4482c702012-06-15 13:27:53 +0000224 public boolean retainAll(Collection< ? > c) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000225 throw new UnsupportedOperationException("Immutable");
226 }
227
Stuart McCulloch4482c702012-06-15 13:27:53 +0000228 public boolean removeAll(Collection< ? > c) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000229 throw new UnsupportedOperationException("Immutable");
230 }
231
232 public void clear() {
233 throw new UnsupportedOperationException("Immutable");
234 }
235
Stuart McCulloch4482c702012-06-15 13:27:53 +0000236 public Comparator< ? super T> comparator() {
Stuart McCullochf3173222012-06-07 21:57:32 +0000237 return cmp;
238 }
239
240 public boolean isSubSet() {
241 return start > 0 && end < list.length;
242 }
243
244 public SortedList<T> subSet(T fromElement, T toElement) {
245 int start = indexOf(fromElement);
246 int end = indexOf(toElement);
247 if (isSubSet() && (start < 0 || end < 0))
248 throw new IllegalArgumentException("This list is a subset");
249 if (start < 0)
250 start = 0;
251 if (end < 0)
252 end = list.length;
253
254 return subList(start, end);
255 }
256
257 public int indexOf(Object o) {
258 assert type != null && type.isInstance(o);
259
260 int n = Arrays.binarySearch(list, (T) o, cmp);
261 if (n >= start && n < end)
262 return n - start;
263
264 return -1;
265 }
266
267 public SortedList<T> headSet(T toElement) {
268 int i = indexOf(toElement);
269 if (i < 0) {
270 if (isSubSet())
271 throw new IllegalArgumentException("This list is a subset");
272 i = end;
273 }
274
275 if (i == end)
276 return this;
277
278 return subList(0, i);
279 }
280
281 public SortedSet<T> tailSet(T fromElement) {
282 int i = indexOf(fromElement);
283 if (i < 0) {
284 if (isSubSet())
285 throw new IllegalArgumentException("This list is a subset");
286 i = start;
287 }
288
289 return subList(i, end);
290 }
291
292 public T first() {
293 if (isEmpty())
294 throw new NoSuchElementException("first");
295 return get(0);
296 }
297
298 public T last() {
299 if (isEmpty())
300 throw new NoSuchElementException("last");
301 return get(end - 1);
302 }
303
Stuart McCulloch4482c702012-06-15 13:27:53 +0000304 @Deprecated
305 public boolean addAll(int index, Collection< ? extends T> c) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000306 throw new UnsupportedOperationException("Immutable");
307 }
308
309 public T get(int index) {
310 return list[index + start];
311 }
312
Stuart McCulloch4482c702012-06-15 13:27:53 +0000313 @Deprecated
314 public T set(int index, T element) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000315 throw new UnsupportedOperationException("Immutable");
316 }
317
Stuart McCulloch4482c702012-06-15 13:27:53 +0000318 @Deprecated
319 public void add(int index, T element) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000320 throw new UnsupportedOperationException("Immutable");
321 }
322
Stuart McCulloch4482c702012-06-15 13:27:53 +0000323 @Deprecated
324 public T remove(int index) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000325 throw new UnsupportedOperationException("Immutable");
326 }
327
328 public int lastIndexOf(Object o) {
329 int n = indexOf(o);
330 if (n < 0)
331 return -1;
332
333 while (cmp.compare(list[n], (T) o) == 0)
334 n++;
335
336 return n;
337 }
338
339 public ListIterator<T> listIterator() {
340 return new It(start);
341 }
342
343 public ListIterator<T> listIterator(int index) {
344 return new It(index + start);
345 }
346
347 public SortedList<T> subList(int fromIndex, int toIndex) {
348 fromIndex += start;
349 toIndex += start;
350
351 if (toIndex < fromIndex) {
352 int tmp = toIndex;
353 toIndex = fromIndex;
354 fromIndex = tmp;
355 }
356
357 toIndex = Math.max(0, toIndex);
358 toIndex = Math.min(toIndex, end);
359 fromIndex = Math.max(0, fromIndex);
360 fromIndex = Math.min(fromIndex, end);
361 if (fromIndex == start && toIndex == end)
362 return this;
363
364 return new SortedList<T>(this, fromIndex, toIndex);
365 }
366
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000367 @Override
Stuart McCulloch4482c702012-06-15 13:27:53 +0000368 @Deprecated
369 public boolean equals(Object other) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000370 return super.equals(other);
371 }
372
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000373 @Override
Stuart McCulloch4482c702012-06-15 13:27:53 +0000374 @Deprecated
375 public int hashCode() {
Stuart McCullochf3173222012-06-07 21:57:32 +0000376 return super.hashCode();
377 }
378
379 public boolean isEqual(SortedList<T> list) {
380 if (size() != list.size())
381 return false;
382
383 for (int as = start, bs = list.start, al = size(); as < al && bs < al; as++, bs++) {
384 if (comparator.compare(this.list[as], this.list[bs]) != 0)
385 return false;
386 }
387 return true;
388 }
389
Stuart McCulloch4482c702012-06-15 13:27:53 +0000390 public Class< ? > getType() {
Stuart McCullochf3173222012-06-07 21:57:32 +0000391 return type;
392 }
393
Stuart McCulloch4482c702012-06-15 13:27:53 +0000394 public void setType(Class< ? > type) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000395 this.type = type;
396 }
397
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000398 @Override
Stuart McCullochf3173222012-06-07 21:57:32 +0000399 public String toString() {
400 StringBuilder sb = new StringBuilder();
401 sb.append("[");
402 String del = "";
403 for (T s : list) {
404 sb.append(del);
405 sb.append(s);
406 del = ", ";
407 }
408
409 sb.append("]");
410 return sb.toString();
411 }
412
413 public boolean hasDuplicates() {
414 if (list.length < 2)
415 return false;
416
417 T prev = list[0];
418 for (int i = 1; i < list.length; i++) {
419 if (prev.equals(list[i]))
420 return true;
421 }
422 return false;
423 }
424
Stuart McCulloch4482c702012-06-15 13:27:53 +0000425 public static <T extends Comparable< ? >> SortedList<T> fromIterator(Iterator<T> it) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000426 IteratorList<T> l = new IteratorList<T>(it);
427 return new SortedList<T>(l);
428 }
429
430 public static <T> SortedList<T> fromIterator(Iterator<T> it, Comparator<T> cmp) {
431 IteratorList<T> l = new IteratorList<T>(it);
432 return new SortedList<T>(l, cmp);
433 }
Stuart McCulloch2a0afd62012-09-06 18:28:06 +0000434
435 public static <T> SortedSet<T> empty() {
436 return (SortedSet<T>) empty;
437 }
Stuart McCullochf3173222012-06-07 21:57:32 +0000438}