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