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.AbstractSet; 13 14 15 import hunt.collection.AbstractCollection; 16 import hunt.collection.Collection; 17 import hunt.collection.Set; 18 19 import hunt.Exceptions; 20 import hunt.Functions; 21 import hunt.Object; 22 23 24 /** 25 * This class provides a skeletal implementation of the <tt>Set</tt> 26 * interface to minimize the effort required to implement this 27 * interface. <p> 28 * 29 * The process of implementing a set by extending this class is identical 30 * to that of implementing a Collection by extending AbstractCollection, 31 * except that all of the methods and constructors in subclasses of this 32 * class must obey the additional constraints imposed by the <tt>Set</tt> 33 * interface (for instance, the add method must not permit addition of 34 * multiple instances of an object to a set).<p> 35 * 36 * Note that this class does not override any of the implementations from 37 * the <tt>AbstractCollection</tt> class. It merely adds implementations 38 * for <tt>equals</tt> and <tt>hashCode</tt>.<p> 39 * 40 * This class is a member of the 41 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 42 * Java Collections Framework</a>. 43 * 44 * @param !(E) the type of elements maintained by this set 45 * 46 * @see Collection 47 * @see AbstractCollection 48 * @see Set 49 */ 50 abstract class AbstractSet(E) : AbstractCollection!E, Set!E { 51 /** 52 * Sole constructor. (For invocation by subclass constructors, typically 53 * implicit.) 54 */ 55 protected this() { 56 } 57 58 // Comparison and hashing 59 60 /** 61 * Compares the specified object with this set for equality. Returns 62 * <tt>true</tt> if the given object is also a set, the two sets have 63 * the same size, and every member of the given set is contained in 64 * this set. This ensures that the <tt>equals</tt> method works 65 * properly across different implementations of the <tt>Set</tt> 66 * interface.<p> 67 * 68 * This implementation first checks if the specified object is this 69 * set; if so it returns <tt>true</tt>. Then, it checks if the 70 * specified object is a set whose size is identical to the size of 71 * this set; if not, it returns false. If so, it returns 72 * <tt>containsAll((Collection) o)</tt>. 73 * 74 * @param o object to be compared for equality with this set 75 * @return <tt>true</tt> if the specified object is equal to this set 76 */ 77 override bool opEquals(Object o) { 78 if(o is null) return false; 79 if (o is this) return true; 80 81 Collection!E c = cast(Collection!E) o; 82 if(c is null) return false; 83 if (c.size() != size()) 84 return false; 85 86 try { 87 return containsAll(c); 88 } catch (Exception) { 89 return false; 90 } 91 } 92 93 override bool opEquals(IObject o) { 94 return opEquals(cast(Object) o); 95 } 96 /** 97 * Returns the hash code value for this set. The hash code of a set is 98 * defined to be the sum of the hash codes of the elements in the set, 99 * where the hash code of a <tt>null</tt> element is defined to be zero. 100 * This ensures that <tt>s1.equals(s2)</tt> implies that 101 * <tt>s1.toHash()==s2.toHash()</tt> for any two sets <tt>s1</tt> 102 * and <tt>s2</tt>, as required by the general contract of 103 * {@link Object#hashCode}. 104 * 105 * <p>This implementation iterates over the set, calling the 106 * <tt>hashCode</tt> method on each element in the set, and adding up 107 * the results. 108 * 109 * @return the hash code value for this set 110 * @see Object#equals(Object) 111 * @see Set#equals(Object) 112 */ 113 override size_t toHash() @trusted nothrow { 114 try { 115 size_t h = 0; 116 foreach(E item; this) 117 h += hashOf(item); 118 return h; 119 } 120 catch(Exception) { 121 return 0; 122 } 123 } 124 125 override string toString() { 126 return super.toString(); 127 } 128 129 /** 130 * Removes from this set all of its elements that are contained in the 131 * specified collection (optional operation). If the specified 132 * collection is also a set, this operation effectively modifies this 133 * set so that its value is the <i>asymmetric set difference</i> of 134 * the two sets. 135 * 136 * <p>This implementation determines which is the smaller of this set 137 * and the specified collection, by invoking the <tt>size</tt> 138 * method on each. If this set has fewer elements, then the 139 * implementation iterates over this set, checking each element 140 * returned by the iterator in turn to see if it is contained in 141 * the specified collection. If it is so contained, it is removed 142 * from this set with the iterator's <tt>remove</tt> method. If 143 * the specified collection has fewer elements, then the 144 * implementation iterates over the specified collection, removing 145 * from this set each element returned by the iterator, using this 146 * set's <tt>remove</tt> method. 147 * 148 * <p>Note that this implementation will throw an 149 * <tt>UnsupportedOperationException</tt> if the iterator returned by the 150 * <tt>iterator</tt> method does not implement the <tt>remove</tt> method. 151 * 152 * @param c collection containing elements to be removed from this set 153 * @return <tt>true</tt> if this set changed as a result of the call 154 * @throws UnsupportedOperationException if the <tt>removeAll</tt> operation 155 * is not supported by this set 156 * @throws ClassCastException if the class of an element of this set 157 * is incompatible with the specified collection 158 * (<a href="Collection.html#optional-restrictions">optional</a>) 159 * @throws NullPointerException if this set contains a null element and the 160 * specified collection does not permit null elements 161 * (<a href="Collection.html#optional-restrictions">optional</a>), 162 * or if the specified collection is null 163 * @see #remove(Object) 164 * @see #contains(Object) 165 */ 166 override bool removeAll(Collection!E c) { 167 assert(c !is null); 168 169 bool modified = false; 170 if (size() > c.size()) { 171 foreach(E k; c) { 172 if(this.contains(k)) { 173 this.remove(k); modified = true; 174 } 175 } 176 } else { 177 foreach(E k; this) { 178 if(c.contains(k)) { 179 this.remove(k); 180 modified = true; 181 } 182 } 183 } 184 return modified; 185 } 186 187 } 188 189 190 /** 191 */ 192 class EmptySet(E) : AbstractSet!(E) { 193 194 // Iterator!(E) iterator() { return emptyIterator(); } 195 196 override int size() {return 0;} 197 override bool isEmpty() {return true;} 198 override void clear() {} 199 200 override bool contains(E obj) {return false;} 201 override bool containsAll(Collection!E c) { return c.isEmpty(); } 202 203 override E[] toArray() { return []; } 204 205 override bool removeIf(Predicate!E filter) { 206 assert(filter !is null); 207 return false; 208 } 209 210 override size_t toHash() @trusted nothrow { 211 return 0; 212 } 213 }