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.AbstractCollection; 13 14 import hunt.collection.Collection; 15 import hunt.Exceptions; 16 import hunt.Functions; 17 import hunt.Object; 18 19 import std.array; 20 import std.conv; 21 import std.range; 22 23 import hunt.logging; 24 25 /** 26 * This class provides a skeletal implementation of the {@code Collection} 27 * interface, to minimize the effort required to implement this interface. <p> 28 * 29 * To implement an unmodifiable collection, the programmer needs only to 30 * extend this class and provide implementations for the {@code iterator} and 31 * {@code size} methods. (The iterator returned by the {@code iterator} 32 * method must implement {@code hasNext} and {@code next}.)<p> 33 * 34 * To implement a modifiable collection, the programmer must additionally 35 * override this class's {@code add} method (which otherwise throws an 36 * {@code UnsupportedOperationException}), and the iterator returned by the 37 * {@code iterator} method must additionally implement its {@code remove} 38 * method.<p> 39 * 40 * The programmer should generally provide a void (no argument) and 41 * {@code Collection} constructor, as per the recommendation in the 42 * {@code Collection} interface specification.<p> 43 * 44 * The documentation for each non-abstract method in this class describes its 45 * implementation in detail. Each of these methods may be overridden if 46 * the collection being implemented admits a more efficient implementation.<p> 47 * 48 * This class is a member of the 49 * <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework"> 50 * Java Collections Framework</a>. 51 * 52 * @author Josh Bloch 53 * @author Neal Gafter 54 * @see Collection 55 */ 56 abstract class AbstractCollection(E) : Collection!E { 57 /** 58 * Sole constructor. (For invocation by subclass constructors, typically 59 * implicit.) 60 */ 61 protected this() { 62 } 63 64 // Query Operations 65 66 /** 67 * Returns an iterator over the elements contained in this collection. 68 * 69 * @return an iterator over the elements contained in this collection 70 */ 71 InputRange!E iterator() { 72 throw new NotImplementedException(); 73 } 74 75 abstract int size(); 76 77 /** 78 * {@inheritDoc} 79 * 80 * <p>This implementation returns <tt>size() == 0</tt>. 81 */ 82 bool isEmpty() { 83 return size() == 0; 84 } 85 86 /** 87 * {@inheritDoc} 88 * 89 * <p>This implementation iterates over the elements in the collection, 90 * checking each element in turn for equality with the specified element. 91 * 92 * @throws ClassCastException {@inheritDoc} 93 * @throws NullPointerException {@inheritDoc} 94 */ 95 bool contains(E o) { 96 // Iterator<E> it = iterator(); 97 // if (o==null) { 98 // while (it.hasNext()) 99 // if (it.next()==null) 100 // return true; 101 // } else { 102 // while (it.hasNext()) 103 // if (o.equals(it.next())) 104 // return true; 105 // } 106 // return false; 107 108 throw new NotImplementedException(); 109 } 110 111 bool add(E e) { 112 throw new NotImplementedException(); 113 } 114 115 bool remove(E e) { 116 throw new NotImplementedException(); 117 } 118 119 // E get(int index) { throw new UnsupportedOperationException(); } 120 121 // Bulk Operations 122 123 /** 124 * {@inheritDoc} 125 * 126 * <p>This implementation iterates over the specified collection, 127 * checking each element returned by the iterator in turn to see 128 * if it's contained in this collection. If all elements are so 129 * contained <tt>true</tt> is returned, otherwise <tt>false</tt>. 130 * 131 * @throws ClassCastException {@inheritDoc} 132 * @throws NullPointerException {@inheritDoc} 133 * @see #contains(Object) 134 */ 135 bool containsAll(Collection!E c) { 136 foreach (E e; c) 137 if (!contains(e)) 138 return false; 139 return true; 140 } 141 142 /** 143 * {@inheritDoc} 144 * 145 * <p>This implementation iterates over the specified collection, and adds 146 * each object returned by the iterator to this collection, in turn. 147 * 148 * <p>Note that this implementation will throw an 149 * <tt>UnsupportedOperationException</tt> unless <tt>add</tt> is 150 * overridden (assuming the specified collection is non-empty). 151 * 152 * @throws UnsupportedOperationException {@inheritDoc} 153 * @throws ClassCastException {@inheritDoc} 154 * @throws NullPointerException {@inheritDoc} 155 * @throws IllegalArgumentException {@inheritDoc} 156 * @throws IllegalStateException {@inheritDoc} 157 * 158 * @see #add(Object) 159 */ 160 bool addAll(Collection!E c) { 161 bool modified = false; 162 foreach (E e; c) { 163 if (add(e)) 164 modified = true; 165 } 166 return modified; 167 } 168 169 bool addAll(E[] c) { 170 bool modified = false; 171 foreach (E e; c) { 172 if (add(e)) 173 modified = true; 174 } 175 return modified; 176 } 177 178 /** 179 * {@inheritDoc} 180 * 181 * <p>This implementation iterates over this collection, checking each 182 * element returned by the iterator in turn to see if it's contained 183 * in the specified collection. If it's so contained, it's removed from 184 * this collection with the iterator's <tt>remove</tt> method. 185 * 186 * <p>Note that this implementation will throw an 187 * <tt>UnsupportedOperationException</tt> if the iterator returned by the 188 * <tt>iterator</tt> method does not implement the <tt>remove</tt> method 189 * and this collection contains one or more elements in common with the 190 * specified collection. 191 * 192 * @throws UnsupportedOperationException {@inheritDoc} 193 * @throws ClassCastException {@inheritDoc} 194 * @throws NullPointerException {@inheritDoc} 195 * 196 * @see #remove(Object) 197 * @see #contains(Object) 198 */ 199 bool removeAll(Collection!E c) { 200 assert(c !is null); 201 bool modified = false; 202 foreach (E k; c) { 203 if (this.contains(k)) { 204 this.remove(k); 205 modified = true; 206 } 207 } 208 209 return modified; 210 } 211 212 bool removeIf(Predicate!E filter) { 213 assert(filter !is null); 214 E[] items; 215 foreach (E item; this) { 216 if (filter(item)) 217 items ~= item; 218 } 219 220 foreach (E item; items) { 221 remove(item); 222 } 223 224 return items.length > 0; 225 } 226 227 /** 228 * {@inheritDoc} 229 * 230 * <p>This implementation iterates over this collection, checking each 231 * element returned by the iterator in turn to see if it's contained 232 * in the specified collection. If it's not so contained, it's removed 233 * from this collection with the iterator's <tt>remove</tt> method. 234 * 235 * <p>Note that this implementation will throw an 236 * <tt>UnsupportedOperationException</tt> if the iterator returned by the 237 * <tt>iterator</tt> method does not implement the <tt>remove</tt> method 238 * and this collection contains one or more elements not present in the 239 * specified collection. 240 * 241 * @throws UnsupportedOperationException {@inheritDoc} 242 * @throws ClassCastException {@inheritDoc} 243 * @throws NullPointerException {@inheritDoc} 244 * 245 * @see #remove(Object) 246 * @see #contains(Object) 247 */ 248 bool retainAll(Collection!E c) { 249 assert(c !is null); 250 bool modified = false; 251 252 // InputRange!E it = iterator(); 253 // while (!it.empty) { 254 // E current = it.front(); 255 // it.popFront(); 256 257 // if (!c.contains(current)) { 258 // // it.remove(); 259 // this.remove(current); 260 // modified = true; 261 // } 262 // } 263 import std.container.slist; 264 265 SList!E list; 266 267 foreach (E k; this) { 268 if (!c.contains(k)) { 269 // this.remove(k); 270 list.insert(k); 271 } 272 } 273 274 modified = !list.empty(); 275 foreach (E e; list) 276 this.remove(e); 277 278 return modified; 279 } 280 281 void clear() { 282 throw new NotImplementedException(); 283 } 284 285 int opApply(scope int delegate(ref E) dg) { 286 throw new NotImplementedException(); 287 // return 0; 288 } 289 290 // int opApply(scope int delegate(MapEntry!(E) entry) dg) { 291 // throw new NotImplementedException(); 292 // } 293 294 /** 295 * {@inheritDoc} 296 * 297 * <p>This implementation returns an array containing all the elements 298 * returned by this collection's iterator, in the same order, stored in 299 * consecutive elements of the array, starting with index {@code 0}. 300 * The length of the returned array is equal to the number of elements 301 * returned by the iterator, even if the size of this collection changes 302 * during iteration, as might happen if the collection permits 303 * concurrent modification during iteration. The {@code size} method is 304 * called only as an optimization hint; the correct result is returned 305 * even if the iterator returns a different number of elements. 306 * 307 * <p>This method is equivalent to: 308 * 309 * <pre> {@code 310 * List<E> list = new ArrayList<E>(size()); 311 * for (E e : this) 312 * list.add(e); 313 * return list.toArray(); 314 * }</pre> 315 */ 316 E[] toArray() { 317 int s = size(); 318 if (s == 0) 319 return []; 320 321 E[] r = new E[s]; 322 int i = 0; 323 foreach (E e; this) { 324 r[i++] = e; 325 } 326 return r; 327 } 328 329 override bool opEquals(IObject o) { 330 return opEquals(cast(Object) o); 331 } 332 333 override bool opEquals(Object o) { 334 return super.opEquals(o); 335 } 336 337 override size_t toHash() @trusted nothrow { 338 return super.toHash(); 339 } 340 341 // string conversion 342 343 /** 344 * Returns a string representation of this collection. The string 345 * representation consists of a list of the collection's elements in the 346 * order they are returned by its iterator, enclosed in square brackets 347 * ({@code "[]"}). Adjacent elements are separated by the characters 348 * {@code ", "} (comma and space). Elements are converted to strings as 349 * by {@link string#valueOf(Object)}. 350 * 351 * @return a string representation of this collection 352 */ 353 override string toString() { 354 if (size() == 0) 355 return "[]"; 356 357 Appender!string sb; 358 sb.put("["); 359 bool isFirst = true; 360 foreach (E e; this) { 361 if (!isFirst) 362 sb.put(", "); 363 static if (is(E == class)) 364 sb.put(e is this ? "(this Collection)" : e.toString()); 365 else 366 sb.put(e.to!string()); 367 isFirst = false; 368 } 369 sb.put(']'); 370 return sb.data; 371 } 372 }