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