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.TreeSet;
13 
14 import hunt.collection.AbstractSet;
15 import hunt.collection.Collection;
16 import hunt.collection.Iterator;
17 import hunt.collection.Map;
18 import hunt.collection.NavigableSet;
19 import hunt.collection.NavigableMap;
20 import hunt.collection.Set;
21 import hunt.collection.SortedSet;
22 import hunt.collection.TreeMap;
23 
24 import hunt.util.Comparator;
25 import hunt.Exceptions;
26 import hunt.Object;
27 
28 import std.range;
29 
30 /**
31  * A {@link NavigableSet} implementation based on a {@link TreeMap}.
32  * The elements are ordered using their {@linkplain Comparable natural
33  * ordering}, or by a {@link Comparator} provided at set creation
34  * time, depending on which constructor is used.
35  *
36  * <p>This implementation provides guaranteed log(n) time cost for the basic
37  * operations ({@code add}, {@code remove} and {@code contains}).
38  *
39  * <p>Note that the ordering maintained by a set (whether or not an explicit
40  * comparator is provided) must be <i>consistent with equals</i> if it is to
41  * correctly implement the {@code Set} interface.  (See {@code Comparable}
42  * or {@code Comparator} for a precise definition of <i>consistent with
43  * equals</i>.)  This is so because the {@code Set} interface is defined in
44  * terms of the {@code equals} operation, but a {@code TreeSet} instance
45  * performs all element comparisons using its {@code compareTo} (or
46  * {@code compare}) method, so two elements that are deemed equal by this method
47  * are, from the standpoint of the set, equal.  The behavior of a set
48  * <i>is</i> well-defined even if its ordering is inconsistent with equals; it
49  * just fails to obey the general contract of the {@code Set} interface.
50  *
51  * <p><strong>Note that this implementation is not synchronized.</strong>
52  * If multiple threads access a tree set concurrently, and at least one
53  * of the threads modifies the set, it <i>must</i> be synchronized
54  * externally.  This is typically accomplished by synchronizing on some
55  * object that naturally encapsulates the set.
56  * If no such object exists, the set should be "wrapped" using the
57  * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet}
58  * method.  This is best done at creation time, to prevent accidental
59  * unsynchronized access to the set: <pre>
60  *   SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));</pre>
61  *
62  * <p>The iterators returned by this class's {@code iterator} method are
63  * <i>fail-fast</i>: if the set is modified at any time after the iterator is
64  * created, in any way except through the iterator's own {@code remove}
65  * method, the iterator will throw a {@link ConcurrentModificationException}.
66  * Thus, in the face of concurrent modification, the iterator fails quickly
67  * and cleanly, rather than risking arbitrary, non-deterministic behavior at
68  * an undetermined time in the future.
69  *
70  * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
71  * as it is, generally speaking, impossible to make any hard guarantees in the
72  * presence of unsynchronized concurrent modification.  Fail-fast iterators
73  * throw {@code ConcurrentModificationException} on a best-effort basis.
74  * Therefore, it would be wrong to write a program that depended on this
75  * exception for its correctness:   <i>the fail-fast behavior of iterators
76  * should be used only to detect bugs.</i>
77  *
78  * <p>This class is a member of the
79  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
80  * Java Collections Framework</a>.
81  *
82  * @param (E) the type of elements maintained by this set
83  *
84  * @author  Josh Bloch
85  * @see     Collection
86  * @see     Set
87  * @see     HashSet
88  * @see     Comparable
89  * @see     Comparator
90  * @see     TreeMap
91  * @since   1.2
92  */
93 
94 class TreeSet(E) : AbstractSet!(E), NavigableSet!(E) //, Cloneable
95 {
96     /**
97      * The backing map.
98      */
99     private NavigableMap!(E, Object) m;
100 
101     // Dummy value to associate with an Object in the backing Map
102     private __gshared static Object PRESENT;
103 
104     shared static this()
105     {
106         PRESENT = new Object();
107     }
108 
109     /**
110      * Constructs a set backed by the specified navigable map.
111      */
112     this(NavigableMap!(E, Object) m) {
113         this.m = m;
114     }
115 
116     /**
117      * Constructs a new, empty tree set, sorted according to the
118      * natural ordering of its elements.  All elements inserted into
119      * the set must implement the {@link Comparable} interface.
120      * Furthermore, all such elements must be <i>mutually
121      * comparable</i>: {@code e1.compareTo(e2)} must not throw a
122      * {@code ClassCastException} for any elements {@code e1} and
123      * {@code e2} in the set.  If the user attempts to add an element
124      * to the set that violates this constraint (for example, the user
125      * attempts to add a string element to a set whose elements are
126      * integers), the {@code add} call will throw a
127      * {@code ClassCastException}.
128      */
129     this() {
130         this(new TreeMap!(E, Object)());
131     }
132 
133     /**
134      * Constructs a new, empty tree set, sorted according to the specified
135      * comparator.  All elements inserted into the set must be <i>mutually
136      * comparable</i> by the specified comparator: {@code comparator.compare(e1,
137      * e2)} must not throw a {@code ClassCastException} for any elements
138      * {@code e1} and {@code e2} in the set.  If the user attempts to add
139      * an element to the set that violates this constraint, the
140      * {@code add} call will throw a {@code ClassCastException}.
141      *
142      * @param comparator the comparator that will be used to order this set.
143      *        If {@code null}, the {@linkplain Comparable natural
144      *        ordering} of the elements will be used.
145      */
146     this(Comparator!E comparator) {
147         this(new TreeMap!(E, Object)(comparator));
148     }
149 
150     /**
151      * Constructs a new tree set containing the elements in the specified
152      * collection, sorted according to the <i>natural ordering</i> of its
153      * elements.  All elements inserted into the set must implement the
154      * {@link Comparable} interface.  Furthermore, all such elements must be
155      * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
156      * {@code ClassCastException} for any elements {@code e1} and
157      * {@code e2} in the set.
158      *
159      * @param c collection whose elements will comprise the new set
160      * @throws ClassCastException if the elements in {@code c} are
161      *         not {@link Comparable}, or are not mutually comparable
162      * @throws NullPointerException if the specified collection is null
163      */
164     this(Collection!E c) {
165         this();
166         addAll(c);
167     }
168 
169     /**
170      * Constructs a new tree set containing the same elements and
171      * using the same ordering as the specified sorted set.
172      *
173      * @param s sorted set whose elements will comprise the new set
174      * @throws NullPointerException if the specified sorted set is null
175      */
176     // this(SortedSet!(E) s) {
177     //     this(s.comparator());
178     //     addAll(s);
179     // }
180 
181     override int opApply(scope int delegate(ref E) dg)  {
182         if(dg is null)
183             throw new NullPointerException();
184         
185         int result = 0;
186         int expectedModCount = m.size();
187         foreach(E k; m.byKey) {
188             result = dg(k);
189             if(result != 0) return result;
190         } 
191         
192         if (expectedModCount !is m.size()) 
193             throw new ConcurrentModificationException();
194         return result;
195     }
196     
197     /**
198      * Returns an iterator over the elements in this set in ascending order.
199      *
200      * @return an iterator over the elements in this set in ascending order
201      */
202     override InputRange!(E) iterator() {
203         return m.byKey();
204         // return m.navigableKeySet().iterator();
205     }
206 
207     /**
208      * Returns an iterator over the elements in this set in descending order.
209      *
210      * @return an iterator over the elements in this set in descending order
211      * @since 1.6
212      */
213     // Iterator!(E) descendingIterator() {
214     //     return m.descendingKeySet().iterator();
215     // }
216 
217     /**
218      * @since 1.6
219      */
220     // NavigableSet!(E) descendingSet() {
221     //     return new TreeSet!(E, Object)(m.descendingMap());
222     // }
223 
224     /**
225      * Returns the number of elements in this set (its cardinality).
226      *
227      * @return the number of elements in this set (its cardinality)
228      */
229     override int size() {
230         return m.size();
231     }
232 
233     /**
234      * Returns {@code true} if this set contains no elements.
235      *
236      * @return {@code true} if this set contains no elements
237      */
238     override bool isEmpty() {
239         return m.isEmpty();
240     }
241 
242     /**
243      * Returns {@code true} if this set contains the specified element.
244      * More formally, returns {@code true} if and only if this set
245      * contains an element {@code e} such that
246      * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
247      *
248      * @param o object to be checked for containment in this set
249      * @return {@code true} if this set contains the specified element
250      * @throws ClassCastException if the specified object cannot be compared
251      *         with the elements currently in the set
252      * @throws NullPointerException if the specified element is null
253      *         and this set uses natural ordering, or its comparator
254      *         does not permit null elements
255      */
256     override bool contains(E o) {
257         return m.containsKey(o);
258     }
259 
260     /**
261      * Adds the specified element to this set if it is not already present.
262      * More formally, adds the specified element {@code e} to this set if
263      * the set contains no element {@code e2} such that
264      * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
265      * If this set already contains the element, the call leaves the set
266      * unchanged and returns {@code false}.
267      *
268      * @param e element to be added to this set
269      * @return {@code true} if this set did not already contain the specified
270      *         element
271      * @throws ClassCastException if the specified object cannot be compared
272      *         with the elements currently in this set
273      * @throws NullPointerException if the specified element is null
274      *         and this set uses natural ordering, or its comparator
275      *         does not permit null elements
276      */
277     override bool add(E e) {
278         return m.put(e, PRESENT) is null;
279     }
280 
281     /**
282      * Removes the specified element from this set if it is present.
283      * More formally, removes an element {@code e} such that
284      * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>,
285      * if this set contains such an element.  Returns {@code true} if
286      * this set contained the element (or equivalently, if this set
287      * changed as a result of the call).  (This set will not contain the
288      * element once the call returns.)
289      *
290      * @param o object to be removed from this set, if present
291      * @return {@code true} if this set contained the specified element
292      * @throws ClassCastException if the specified object cannot be compared
293      *         with the elements currently in this set
294      * @throws NullPointerException if the specified element is null
295      *         and this set uses natural ordering, or its comparator
296      *         does not permit null elements
297      */
298     override bool remove(E o) {
299         return m.remove(o)==PRESENT;
300     }
301 
302     /**
303      * Removes all of the elements from this set.
304      * The set will be empty after this call returns.
305      */
306     override void clear() {
307         m.clear();
308     }
309 
310     /**
311      * Adds all of the elements in the specified collection to this set.
312      *
313      * @param c collection containing elements to be added to this set
314      * @return {@code true} if this set changed as a result of the call
315      * @throws ClassCastException if the elements provided cannot be compared
316      *         with the elements currently in the set
317      * @throws NullPointerException if the specified collection is null or
318      *         if any element is null and this set uses natural ordering, or
319      *         its comparator does not permit null elements
320      */
321      override bool addAll(Collection!(E) c) {
322         // Use linear-time version if applicable
323         // if (m.size()==0 && c.size() > 0 &&
324         //     c instanceof SortedSet &&
325         //     m instanceof TreeMap) {
326         //     SortedSet!(E) set = (SortedSet!(E)) c;
327         //     TreeMap!(E, Object) map = (TreeMap<E, Object>) m;
328         //     Comparator<?> cc = set.comparator();
329         //     Comparator<E> mc = map.comparator();
330         //     if (cc==mc || (cc !is null && cc.equals(mc))) {
331         //         map.addAllForTreeSet(set, PRESENT);
332         //         return true;
333         //     }
334         // }
335         return super.addAll(c);
336     }
337 
338     /**
339      * @throws ClassCastException {@inheritDoc}
340      * @throws NullPointerException if {@code fromElement} or {@code toElement}
341      *         is null and this set uses natural ordering, or its comparator
342      *         does not permit null elements
343      * @throws IllegalArgumentException {@inheritDoc}
344      * @since 1.6
345      */
346     NavigableSet!(E) subSet(E fromElement, bool fromInclusive,
347                                   E toElement,   bool toInclusive) {
348         return new TreeSet!(E)(m.subMap(fromElement, fromInclusive,
349                                        toElement,   toInclusive));
350     }
351 
352     /**
353      * @throws ClassCastException {@inheritDoc}
354      * @throws NullPointerException if {@code toElement} is null and
355      *         this set uses natural ordering, or its comparator does
356      *         not permit null elements
357      * @throws IllegalArgumentException {@inheritDoc}
358      * @since 1.6
359      */
360     NavigableSet!(E) headSet(E toElement, bool inclusive) {
361         return new TreeSet!(E)(m.headMap(toElement, inclusive));
362     }
363 
364     /**
365      * @throws ClassCastException {@inheritDoc}
366      * @throws NullPointerException if {@code fromElement} is null and
367      *         this set uses natural ordering, or its comparator does
368      *         not permit null elements
369      * @throws IllegalArgumentException {@inheritDoc}
370      * @since 1.6
371      */
372     NavigableSet!(E) tailSet(E fromElement, bool inclusive) {
373         return new TreeSet!(E)(m.tailMap(fromElement, inclusive));
374     }
375 
376     /**
377      * @throws ClassCastException {@inheritDoc}
378      * @throws NullPointerException if {@code fromElement} or
379      *         {@code toElement} is null and this set uses natural ordering,
380      *         or its comparator does not permit null elements
381      * @throws IllegalArgumentException {@inheritDoc}
382      */
383     SortedSet!(E) subSet(E fromElement, E toElement) {
384         return subSet(fromElement, true, toElement, false);
385     }
386 
387     /**
388      * @throws ClassCastException {@inheritDoc}
389      * @throws NullPointerException if {@code toElement} is null
390      *         and this set uses natural ordering, or its comparator does
391      *         not permit null elements
392      * @throws IllegalArgumentException {@inheritDoc}
393      */
394     SortedSet!(E) headSet(E toElement) {
395         return headSet(toElement, false);
396     }
397 
398     /**
399      * @throws ClassCastException {@inheritDoc}
400      * @throws NullPointerException if {@code fromElement} is null
401      *         and this set uses natural ordering, or its comparator does
402      *         not permit null elements
403      * @throws IllegalArgumentException {@inheritDoc}
404      */
405     SortedSet!(E) tailSet(E fromElement) {
406         return tailSet(fromElement, true);
407     }
408 
409     Comparator!(E) comparator() {
410         return m.comparator();
411     }
412 
413     /**
414      * @throws NoSuchElementException {@inheritDoc}
415      */
416     E first() {
417         return m.firstKey();
418     }
419 
420     /**
421      * @throws NoSuchElementException {@inheritDoc}
422      */
423     E last() {
424         return m.lastKey();
425     }
426 
427     // NavigableSet API methods
428 
429     /**
430      * @throws ClassCastException {@inheritDoc}
431      * @throws NullPointerException if the specified element is null
432      *         and this set uses natural ordering, or its comparator
433      *         does not permit null elements
434      * @since 1.6
435      */
436     E lower(E e) {
437         return m.lowerKey(e);
438     }
439 
440     /**
441      * @throws ClassCastException {@inheritDoc}
442      * @throws NullPointerException if the specified element is null
443      *         and this set uses natural ordering, or its comparator
444      *         does not permit null elements
445      * @since 1.6
446      */
447     E floor(E e) {
448         return m.floorKey(e);
449     }
450 
451     /**
452      * @throws ClassCastException {@inheritDoc}
453      * @throws NullPointerException if the specified element is null
454      *         and this set uses natural ordering, or its comparator
455      *         does not permit null elements
456      * @since 1.6
457      */
458     E ceiling(E e) {
459         return m.ceilingKey(e);
460     }
461 
462     /**
463      * @throws ClassCastException {@inheritDoc}
464      * @throws NullPointerException if the specified element is null
465      *         and this set uses natural ordering, or its comparator
466      *         does not permit null elements
467      * @since 1.6
468      */
469     E higher(E e) {
470         return m.higherKey(e);
471     }
472 
473     /**
474      * @since 1.6
475      */
476     E pollFirst() {
477         MapEntry!(E, Object) e = m.pollFirstEntry();
478         static if(is(E == class) || is(E == interface)) {
479             return (e is null) ? null : e.getKey();
480         } else
481             return e.getKey();
482     }
483 
484     /**
485      * @since 1.6
486      */
487     E pollLast() {
488         MapEntry!(E, Object) e = m.pollLastEntry();
489         static if(is(E == class) || is(E == interface)) {
490             return (e is null) ? null : e.getKey();
491         } else
492             return e.getKey();
493     }
494 
495     /**
496      * Returns a shallow copy of this {@code TreeSet} instance. (The elements
497      * themselves are not cloned.)
498      *
499      * @return a shallow copy of this set
500      */
501     // Object clone() {
502     //     TreeSet!(E) clone;
503     //     try {
504     //         clone = (TreeSet!(E)) super.clone();
505     //     } catch (CloneNotSupportedException e) {
506     //         throw new InternalError(e);
507     //     }
508 
509     //     clone.m = new TreeMap<>(m);
510     //     return clone;
511     // }
512 
513     /**
514      * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
515      * and <em>fail-fast</em> {@link Spliterator} over the elements in this
516      * set.
517      *
518      * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
519      * {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED}, and
520      * {@link Spliterator#ORDERED}.  Overriding implementations should document
521      * the reporting of additional characteristic values.
522      *
523      * <p>The spliterator's comparator (see
524      * {@link java.util.Spliterator#getComparator()}) is {@code null} if
525      * the tree set's comparator (see {@link #comparator()}) is {@code null}.
526      * Otherwise, the spliterator's comparator is the same as or imposes the
527      * same total ordering as the tree set's comparator.
528      *
529      * @return a {@code Spliterator} over the elements in this set
530      * @since 1.8
531      */
532     // Spliterator!(E) spliterator() {
533     //     return TreeMap.keySpliteratorFor(m);
534     // }
535 
536     override bool opEquals(IObject o) {
537         return opEquals(cast(Object) o);
538     }
539     
540     override bool opEquals(Object o) {
541         return super.opEquals(o);
542     }
543 
544     override size_t toHash() @trusted nothrow {
545         return super.toHash();
546     }
547 
548     override string toString() {
549         return super.toString();
550     }    
551 }