1 module java.util.HashSet;
2 
3 import java.lang.all;
4 import java.util.Set;
5 import java.util.Collection;
6 import java.util.Iterator;
7 
8 version(Tango){
9     static import tango.util.container.HashSet;
10 } else { // Phobos
11 }
12 
13 /**
14  * This class implements the {@code Set} interface, backed by a hash table
15  * (actually a {@code HashMap} instance).  It makes no guarantees as to the
16  * iteration order of the set; in particular, it does not guarantee that the
17  * order will remain constant over time.  This class permits the {@code null}
18  * element.
19  */
20 class HashSet : Set {
21     version(Tango){
22         alias tango.util.container.HashSet.HashSet!(Object) SetType;
23         private SetType set;
24     } else { // Phobos
25         alias SetType = void[0][Object];
26         private SetType set;
27     }
28 
29     /**
30      * Constructs a new, empty set.
31      */
32     public this(){
33         version(Tango){
34             set = new SetType();
35         } else { // Phobos
36             // already initialized (to null)
37         }
38     }
39 
40     /**
41      * Constructs a new set containing the elements in the specified
42      * collection.
43      *
44      * @param c the collection whose elements are to be placed into this set.
45      */
46     public this(Collection c){
47         version(Tango){
48             set = new SetType();
49             addAll(c);
50         } else { // Phobos
51             // already initialized (to null)
52             this.addAll(c);
53         }
54     }
55 
56     /**
57      * Constructs a new, empty set.
58      *
59      * D2/Phobos: This method has no difference compared to `this()`.
60      *
61      * @param initialCapacity the initial capacity of the hash table.
62      */
63     public this(int initialCapacity){
64         version(Tango){
65             set = new SetType();
66         } else { // Phobos
67             // already initialized (to null)
68         }
69     }
70 
71     /**
72      * Constructs a new, empty set.
73      *
74      * D2/Phobos: This method has no difference compared to `this()`.
75      *
76      * @param initialCapacity the initial capacity of the hash map
77      * @param loadFactor the load factor of the hash map
78      */
79     public this(int initialCapacity, float loadFactor){
80         version(Tango){
81             set = new SetType(loadFactor);
82         } else { // Phobos
83             // already initialized (to null)
84         }
85     }
86 
87     /**
88      * Adds the specified element to this set if it is not already present.
89      * More formally, adds the specified element {@code e} to this set if
90      * this set contains no element {@code e2} such that
91      * {@code Objects.equals(e, e2)}.
92      * If this set already contains the element, the call leaves the set
93      * unchanged and returns {@code false}.
94      *
95      * @param e element to be added to this set
96      * @return {@code true} if this set did not already contain the specified
97      * element
98      */
99     public bool add(Object o) {
100         version(Tango) {
101             return set.add(o);
102         } else { // Phobos
103             static if (__traits(hasMember, .object, "update"))
104             {
105                 bool res = false;
106                 set.update(o, {
107                     res = true;
108                     return (void[0]).init;
109                 }, (ref void[0] v) {
110                     /* Keep "return" for D versions < 2.092.0 */
111                     return v;
112                 });
113                 return res;
114             }
115             else
116             {
117                 /* D versions < 2.082.0  */
118                 if (this.contains(o)) return false;
119                 set[o] = (void[0]).init;
120                 return true;
121             }
122         }
123     }
124 
125     /// Ditto
126     public bool add(String o) {
127         return add(stringcast(o));
128     }
129 
130     /**
131      * Adds all of the elements in the specified collection to this set if
132      * they're not already present (optional operation).  If the specified
133      * collection is also a set, the {@code addAll} operation effectively
134      * modifies this set so that its value is the <i>union</i> of the two
135      * sets.  The behavior of this operation is undefined if the specified
136      * collection is modified while the operation is in progress.
137      *
138      * @param  c collection containing elements to be added to this set
139      * @return {@code true} if this set changed as a result of the call
140      *
141      * @throws UnsupportedOperationException if the {@code addAll} operation
142      *         is not supported by this set
143      * @throws ClassCastException if the class of an element of the
144      *         specified collection prevents it from being added to this set
145      * @throws NullPointerException if the specified collection contains one
146      *         or more null elements and this set does not permit null
147      *         elements, or if the specified collection is null
148      * @throws IllegalArgumentException if some property of an element of the
149      *         specified collection prevents it from being added to this set
150      * @see #add(Object)
151      */
152     public bool addAll(Collection c) {
153         bool res = false;
154         foreach( o; c ){
155             res |= add(o);
156         }
157         return res;
158     }
159 
160     /**
161      * Removes all of the elements from this set.
162      * The set will be empty after this call returns.
163      */
164     public void clear() {
165         version(Tango) {
166             set.clear();
167         } else { // Phobos
168             set.clear();
169         }
170     }
171 
172     /**
173      * Returns {@code true} if this set contains the specified element.
174      * More formally, returns {@code true} if and only if this set
175      * contains an element {@code e} such that
176      * {@code Objects.equals(o, e)}.
177      *
178      * @param o element whose presence in this set is to be tested
179      * @return {@code true} if this set contains the specified element
180      */
181     public bool contains(Object o){
182         version(Tango){
183             return set.contains(o);
184         } else { // Phobos
185             foreach (e; set.byKey)
186             {
187                 if (o is null && e is null) return true;
188                 if (o == e) return true;
189             }
190             return false;
191         }
192     }
193 
194     /// Ditto
195     public bool contains(String o) {
196         return contains(stringcast(o));
197     }
198 
199     public bool    containsAll(Collection c){
200         implMissing( __FILE__, __LINE__ );
201         return false;
202     }
203     public override equals_t    opEquals(Object o){
204         implMissing( __FILE__, __LINE__ );
205         return 0;
206     }
207     public override hash_t    toHash(){
208         implMissingSafe( __FILE__, __LINE__ );
209         return 0;
210     }
211 
212     /**
213      * Returns {@code true} if this set contains no elements.
214      *
215      * @return {@code true} if this set contains no elements
216      */
217     public bool isEmpty() {
218         version(Tango){
219             return set.isEmpty();
220         } else { // Phobos
221             import std.range : empty;
222             return empty(set);
223         }
224     }
225 
226     version(Tango){
227         class LocalIterator : Iterator {
228             SetType.Iterator iter;
229             Object nextElem;
230             this( SetType.Iterator iter){
231                 this.iter = iter;
232             }
233             public bool hasNext(){
234                 return iter.next(nextElem);
235             }
236             public Object next(){
237                 return nextElem;
238             }
239             public void  remove(){
240                 iter.remove();
241             }
242         }
243     } else { // Phobos
244     }
245     public Iterator   iterator(){
246         version(Tango){
247             return new LocalIterator(set.iterator());
248         } else { // Phobos
249             implMissingInPhobos();
250             return null;
251         }
252     }
253 
254     /**
255      * Removes the specified element from this set if it is present.
256      * More formally, removes an element {@code e} such that
257      * {@code Objects.equals(o, e)},
258      * if this set contains such an element.  Returns {@code true} if
259      * this set contained the element (or equivalently, if this set
260      * changed as a result of the call).  (This set will not contain the
261      * element once the call returns.)
262      *
263      * @param o object to be removed from this set, if present
264      * @return {@code true} if the set contained the specified element
265      */
266     public bool remove(Object o) {
267         version(Tango) {
268             return set.remove(o);
269         } else { // Phobos
270             return set.remove(o);
271         }
272     }
273 
274     /// Ditto
275     public bool remove(String o){
276         return remove(stringcast(o));
277     }
278 
279     public bool    removeAll(Collection c){
280         implMissing( __FILE__, __LINE__ );
281         return false;
282     }
283     public bool    retainAll(Collection c){
284         implMissing( __FILE__, __LINE__ );
285         return false;
286     }
287 
288     /**
289      * Returns the number of elements in this set (its cardinality).
290      *
291      * @return the number of elements in this set (its cardinality)
292      */
293     public int    size(){
294         version(Tango){
295             return set.size();
296         } else { // Phobos
297             return cast(int)set.length;
298         }
299     }
300 
301     /**
302      * Returns an array containing all of the elements in this set.
303      * If this set makes any guarantees as to what order its elements
304      * are returned by its iterator, this method must return the
305      * elements in the same order.
306      *
307      * <p>The returned array will be "safe" in that no references to it
308      * are maintained by this set.  (In other words, this method must
309      * allocate a new array even if this set is backed by an array).
310      * The caller is thus free to modify the returned array.
311      *
312      * <p>This method acts as bridge between array-based and collection-based
313      * APIs.
314      *
315      * @return an array containing all the elements in this set
316      */
317     public Object[] toArray(){
318         version(Tango){
319             Object[] res;
320             res.length = size();
321             int idx = 0;
322             foreach( o; set ){
323                 res[idx] = o;
324                 idx++;
325             }
326             return res;
327         } else { // Phobos
328             return set.keys;
329         }
330     }
331 
332     public Object[]   toArray(Object[] a){
333         implMissing( __FILE__, __LINE__ );
334         return null;
335     }
336     public override String toString(){
337         implMissing( __FILE__, __LINE__ );
338         return null;
339     }
340 
341     // only for D
342     public int opApply (int delegate(ref Object value) dg){
343         version(Tango){
344             return set.opApply(dg);
345         } else { // Phobos
346             int result = 0;
347             foreach(e; set.byKey) {
348                 result = dg(e);
349 
350                 if (result)
351                     break;
352             }
353             return result;
354         }
355     }
356 }