1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.collection.Collections;
13 
14 
15 import hunt.collection.AbstractList;
16 import hunt.collection.AbstractMap;
17 import hunt.collection.AbstractSet;
18 import hunt.collection.Collection;
19 import hunt.collection.Enumeration;
20 import hunt.collection.List;
21 import hunt.collection.NavigableSet;
22 import hunt.collection.Map;
23 import hunt.collection.Set;
24 import hunt.collection.SortedSet;
25 import hunt.collection.TreeSet;
26 
27 import hunt.Functions;
28 import hunt.Exceptions;
29 import hunt.Object;
30 
31 import std.conv;
32 import std.range;
33 
34 
35 
36 /**
37 */
38 class Collections {
39     // Suppresses default constructor, ensuring non-instantiability.
40 
41     private this() {
42     }
43 
44     static Enumeration!T enumeration(T=string)(InputRange!T range)
45     {
46         return new RangeEnumeration!T(range);
47     }
48 
49     static Enumeration!T enumeration(T=string)(T[] range)
50     {
51         return new RangeEnumeration!T(inputRangeObject(range));
52     }
53 
54     /**
55      * Returns true if the specified arguments are equal, or both null.
56      *
57      * NB: Do not replace with Object.equals until JDK-8015417 is resolved.
58      */
59     // static bool eq(Object o1, Object o2) {
60     //     return o1 is null ? o2 is null : o1.opEquals(o2);
61     // }
62 
63     /**
64      * Returns an empty map (immutable).  This map is serializable.
65      *
66      * !(p)This example illustrates the type-safe way to obtain an empty map:
67      * !(pre)
68      *     Map<string, Date> s = Collections.emptyMap();
69      * !(/pre)
70      * @implNote Implementations of this method need not create a separate
71      * {@code Map} object for each call.  Using this method is likely to have
72      * comparable cost to using the like-named field.  (Unlike this method, the
73      * field does not provide type safety.)
74      *
75      * @param (K) the class of the map keys
76      * @param (V) the class of the map values
77      * @return an empty map
78      * @see #EMPTY_MAP
79      */
80     static Map!(K,V) emptyMap(K,V)() {
81         return new EmptyMap!(K,V)();
82     }
83 
84     /**
85      * Returns an empty navigable set (immutable).  This set is serializable.
86      *
87      * <p>This example illustrates the type-safe way to obtain an empty
88      * navigable set:
89      * <pre> {@code
90      *     NavigableSet!(string) s = Collections.emptyNavigableSet();
91      * }</pre>
92      *
93      * @implNote Implementations of this method need not
94      * create a separate {@code NavigableSet} object for each call.
95      *
96      * @param !E type of elements, if there were any, in the set
97      * @return the empty navigable set
98      */
99     static NavigableSet!(E) emptyNavigableSet(E)() {
100         return new EmptyNavigableSet!(E)();
101     }
102     
103 
104     // Singleton collections
105 
106     /**
107      * Returns an immutable set containing only the specified object.
108      * The returned set is serializable.
109      *
110      * @param  !(T) the class of the objects in the set
111      * @param o the sole object to be stored in the returned set.
112      * @return an immutable set containing only the specified object.
113      */
114     static Set!T singleton(T)(T o) {
115         return new SingletonSet!T(o);
116     }
117     
118 
119     /**
120      * Returns an immutable list containing only the specified object.
121      * The returned list is serializable.
122      *
123      * @param  !(T) the class of the objects in the list
124      * @param o the sole object to be stored in the returned list.
125      * @return an immutable list containing only the specified object.
126      */
127     static List!T singletonList(T)(T o) {
128         return new SingletonList!T(o);
129     }
130 
131     static List!T emptyList(T)()
132     {
133         return new EmptyList!T();
134     }
135 
136     static Set!T emptySet(T)() {
137         return new EmptySet!T();
138     }
139     
140 }
141 
142 
143 
144 private class SingletonSet(E) : AbstractSet!E
145 {
146 
147     private E element;
148 
149     this(E e) {element = e;}
150 
151     override bool remove(E o) {
152         return true;
153     }
154     override
155     int size() {return 1;}
156 
157     override bool contains(E)(E o) {return o == element;}
158 
159     override
160     int opApply(scope int delegate(ref E) dg) {
161         dg(element);
162         return 0;
163     }
164 
165     // Override default methods for Collection
166     // override
167     // void forEach(Consumer!E action) {
168     //     action.accept(element);
169     // }
170 
171     // override
172     // Spliterator!E spliterator() {
173     //     return singletonSpliterator(element);
174     // }
175 
176     override
177     bool removeIf(Predicate!E filter) {
178         throw new UnsupportedOperationException();
179     }
180 }
181 
182 
183 /**
184 * @serial include
185 */
186 private static class SingletonList(E)  : AbstractList!E    {
187 
188     // private enum long serialVersionUID = 3093736618740652951L;
189 
190     private E element;
191 
192     this(E obj)                {element = obj;}
193 
194     // Iterator!E iterator() {
195     //     return singletonIterator(element);
196     // }
197 
198     override int size() {return 1;}
199 
200     override bool contains(E obj) {
201         static if(is(E == class))
202             return cast(Object)obj == cast(Object)element;
203         else
204             return element == obj;
205         }
206 
207     override E get(int index) {
208         if (index != 0)
209             throw new IndexOutOfBoundsException("Index: " ~ index.to!string  ~ ", Size: 1");
210         return element;
211     }
212 
213     // Override default methods for Collection
214     override
215     int opApply(scope int delegate(ref E) dg)
216     {
217         dg(element);
218         return 0;
219     }
220 
221     // override
222     // boole removeIf(Predicate!E filter) {
223     //     throw new UnsupportedOperationException();
224     // }
225     // override
226     // void replaceAll(UnaryOperator!E operator) {
227     //     throw new UnsupportedOperationException();
228     // }
229     // override
230     // void sort(Comparator!(E) c) {
231     // }
232     // override
233     // Spliterator!E spliterator() {
234     //     return singletonSpliterator(element);
235     // }
236 }
237 
238 
239 /**
240 * @serial include
241 */
242 private class UnmodifiableCollection(E) : Collection!(E) {
243     // private static final long serialVersionUID = 1820017752578914078L;
244 
245     protected Collection!(E) c;
246 
247     this(Collection!(E) c) {
248         if (c is null)
249             throw new NullPointerException();
250         this.c = c;
251     }
252 
253     int size()                   {return c.size();}
254     bool isEmpty()            {return c.isEmpty();}
255     bool contains(E o)   {return c.contains(o);}
256     E[] toArray()           {return c.toArray();}
257     // !(T) T[] toArray(T[] a)       {return c.toArray(a);}
258     override string toString()            {return c.toString();}
259     
260     override size_t toHash() @trusted nothrow { return super.toHash(); }
261 
262     InputRange!E iterator() {
263         throw new NotImplementedException();
264     }
265 
266 
267     // Iterator!(E) iterator() {
268     //     return new Iterator!(E)() {
269     //         private final Iterator!(E) i = c.iterator();
270 
271     //         bool hasNext() {return i.hasNext();}
272     //         E next()          {return i.next();}
273     //         void remove() {
274     //             throw new UnsupportedOperationException();
275     //         }
276     //         override
277     //         void forEachRemaining(Consumer!E action) {
278     //             // Use backing collection version
279     //             i.forEachRemaining(action);
280     //         }
281     //     };
282     // }
283 
284     bool add(E e) {
285         throw new UnsupportedOperationException();
286     }
287 
288     bool addAll(E[] e) {
289         throw new UnsupportedOperationException();
290     }
291     
292     bool remove(E o) {
293         throw new UnsupportedOperationException();
294     }
295 
296     bool containsAll(Collection!(E) coll) {
297         return c.containsAll(coll);
298     }
299     bool addAll(Collection!(E) coll) {
300         throw new UnsupportedOperationException();
301     }
302     bool removeAll(Collection!(E) coll) {
303         throw new UnsupportedOperationException();
304     }
305     bool retainAll(Collection!(E) coll) {
306         throw new UnsupportedOperationException();
307     }
308     void clear() {
309         throw new UnsupportedOperationException();
310     }
311 
312     // Override default methods in Collection
313     // override
314     // void forEach(Consumer!(E) action) {
315     //     c.forEach(action);
316     // }
317     int opApply(scope int delegate(ref E) dg) {
318         int r = 0;
319         foreach(E e; c) {
320             r = dg(e);
321             if(r != 0) return r;
322         }
323         return r;
324     }
325 
326     override
327     bool removeIf(Predicate!(E) filter) {
328         throw new UnsupportedOperationException();
329     }
330     
331     bool opEquals(IObject o) {
332         return opEquals(cast(Object) o);
333     }
334 
335     alias opEquals = Object.opEquals;
336 
337     // override
338     // Spliterator!(E) spliterator() {
339     //     return (Spliterator!(E))c.spliterator();
340     // }
341     
342     // override
343     // Stream!(E) stream() {
344     //     return (Stream!(E))c.stream();
345     // }
346     
347     // override
348     // Stream!(E) parallelStream() {
349     //     return (Stream!(E))c.parallelStream();
350     // }
351 }
352 
353 /**
354 * @serial include
355 */
356 private class UnmodifiableSet(E) : UnmodifiableCollection!(E), Set!(E) {
357     // private static final long serialVersionUID = -9215047833775013803L;
358 
359     this(Set!(E) s)     {super(s);}
360     override bool opEquals(Object o) {return o is this || c == o;} 
361     
362     override bool opEquals(IObject o) {
363         return opEquals(cast(Object) o);
364     }
365 
366     override string toString() {
367         return super.toString();
368     }
369 
370     override size_t toHash() @trusted nothrow           { return c.toHash();}
371 }
372 
373 /**
374 * A singleton empty unmodifiable navigable set used for
375 * {@link #emptyNavigableSet()}.
376 *
377 * @param (E) type of elements, if there were any, and bounds
378 */
379 private class EmptyNavigableSet(E) : UnmodifiableNavigableSet!(E) {
380     // private static final long serialVersionUID = -6291252904449939134L;
381 
382     this() {
383         super(new TreeSet!(E)());
384     }
385 
386     // private Object readResolve()        { return EMPTY_NAVIGABLE_SET; }
387 }
388 
389 /**
390 * @serial include
391 */
392 private class UnmodifiableSortedSet(E) : UnmodifiableSet!(E), SortedSet!(E) {
393         // private static final long serialVersionUID = -4929149591599911165L;
394     private SortedSet!(E) ss;
395 
396     this(SortedSet!(E) s) {super(s); ss = s;}
397 
398     // Comparator!E comparator() {return ss.comparator();}
399 
400     SortedSet!(E) subSet(E fromElement, E toElement) {
401         return new UnmodifiableSortedSet!(E)(ss.subSet(fromElement,toElement));
402     }
403     SortedSet!(E) headSet(E toElement) {
404         return new UnmodifiableSortedSet!(E)(ss.headSet(toElement));
405     }
406     SortedSet!(E) tailSet(E fromElement) {
407         return new UnmodifiableSortedSet!(E)(ss.tailSet(fromElement));
408     }
409 
410     E first()                   {return ss.first();}
411     E last()                    {return ss.last();}
412 
413 
414     override bool opEquals(IObject o) {
415         return opEquals(cast(Object) o);
416     }
417     
418     alias opEquals = Object.opEquals;
419 
420     override string toString() {
421         return super.toString();
422     }
423 
424     override size_t toHash() @trusted nothrow {
425         return super.toHash();
426     }
427 
428 }
429 
430 
431 /**
432 * Wraps a navigable set and disables all of the mutative operations.
433 *
434 * @param (E) type of elements
435 * @serial include
436 */
437 private class UnmodifiableNavigableSet(E) : 
438     UnmodifiableSortedSet!(E), NavigableSet!(E) {
439 
440     /**
441     * The instance we are protecting.
442     */
443     private NavigableSet!(E) ns;
444 
445     this(NavigableSet!(E) s)         {super(s); ns = s;}
446 
447     E lower(E e)                             { return ns.lower(e); }
448     E floor(E e)                             { return ns.floor(e); }
449     E ceiling(E e)                         { return ns.ceiling(e); }
450     E higher(E e)                           { return ns.higher(e); }
451     E pollFirst()     { throw new UnsupportedOperationException(); }
452     E pollLast()      { throw new UnsupportedOperationException(); }
453     // NavigableSet!(E) descendingSet()
454     //             { return new UnmodifiableNavigableSet!(E)(ns.descendingSet()); }
455     // Iterator!(E) descendingIterator()
456     //                                     { return descendingSet().iterator(); }
457 
458     NavigableSet!(E) subSet(E fromElement, bool fromInclusive, E toElement, bool toInclusive) {
459         return new UnmodifiableNavigableSet!(E)(
460             ns.subSet(fromElement, fromInclusive, toElement, toInclusive));
461     }
462 
463     NavigableSet!(E) headSet(E toElement, bool inclusive) {
464         return new UnmodifiableNavigableSet!(E)(
465             ns.headSet(toElement, inclusive));
466     }
467 
468     NavigableSet!(E) tailSet(E fromElement, bool inclusive) {
469         return new UnmodifiableNavigableSet!(E)(
470             ns.tailSet(fromElement, inclusive));
471     }
472 
473     override SortedSet!(E) subSet(E fromElement, E toElement) {
474         return new UnmodifiableSortedSet!(E)(ss.subSet(fromElement,toElement));
475     }
476     override SortedSet!(E) headSet(E toElement) {
477         return new UnmodifiableSortedSet!(E)(ss.headSet(toElement));
478     }
479     override SortedSet!(E) tailSet(E fromElement) {
480         return new UnmodifiableSortedSet!(E)(ss.tailSet(fromElement));
481     }
482 
483     // alias subSet = UnmodifiableSortedSet!(E).subSet;
484     // alias headSet = UnmodifiableSortedSet!(E).headSet;
485     // alias tailSet = UnmodifiableSortedSet!(E).tailSet;
486 
487     override bool opEquals(IObject o) {
488         return opEquals(cast(Object) o);
489     }
490 
491     alias opEquals = Object.opEquals;
492 
493     override string toString() {
494         return super.toString();
495     }
496 
497     override size_t toHash() @trusted nothrow {
498         return super.toHash();
499     }
500 
501     // alias toString = Object.toString;
502     // alias toHash = Object.toHash;
503 
504 }