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.AbstractList; 13 14 import std.algorithm; 15 import std.conv; 16 import std.traits; 17 18 import hunt.collection.AbstractCollection; 19 import hunt.collection.List; 20 import hunt.Exceptions; 21 import hunt.Object; 22 import hunt.util.Comparator; 23 24 /** 25 */ 26 abstract class AbstractList(E) : AbstractCollection!E, List!E { 27 28 /** 29 * The number of times this list has been <i>structurally modified</i>. 30 * Structural modifications are those that change the size of the 31 * list, or otherwise perturb it in such a fashion that iterations in 32 * progress may yield incorrect results. 33 * 34 * <p>This field is used by the iterator and list iterator implementation 35 * returned by the {@code iterator} and {@code listIterator} methods. 36 * If the value of this field changes unexpectedly, the iterator (or list 37 * iterator) will throw a {@code ConcurrentModificationException} in 38 * response to the {@code next}, {@code remove}, {@code previous}, 39 * {@code set} or {@code add} operations. This provides 40 * <i>fail-fast</i> behavior, rather than non-deterministic behavior in 41 * the face of concurrent modification during iteration. 42 * 43 * <p><b>Use of this field by subclasses is optional.</b> If a subclass 44 * wishes to provide fail-fast iterators (and list iterators), then it 45 * merely has to increment this field in its {@code add(int, E)} and 46 * {@code remove(int)} methods (and any other methods that it overrides 47 * that result in structural modifications to the list). A single call to 48 * {@code add(int, E)} or {@code remove(int)} must add no more than 49 * one to this field, or the iterators (and list iterators) will throw 50 * bogus {@code ConcurrentModificationExceptions}. If an implementation 51 * does not wish to provide fail-fast iterators, this field may be 52 * ignored. 53 */ 54 protected int modCount = 0; 55 56 /** 57 * Sole constructor. (For invocation by subclass constructors, typically 58 * implicit.) 59 */ 60 protected this() { 61 } 62 63 /** 64 * Appends the specified element to the end of this list (optional 65 * operation). 66 * 67 * <p>Lists that support this operation may place limitations on what 68 * elements may be added to this list. In particular, some 69 * lists will refuse to add null elements, and others will impose 70 * restrictions on the type of elements that may be added. List 71 * classes should clearly specify in their documentation any restrictions 72 * on what elements may be added. 73 * 74 * <p>This implementation calls {@code add(size(), e)}. 75 * 76 * <p>Note that this implementation throws an 77 * {@code UnsupportedOperationException} unless 78 * {@link #add(int, Object) add(int, E)} is overridden. 79 * 80 * @param e element to be appended to this list 81 * @return {@code true} (as specified by {@link Collection#add}) 82 * @throws UnsupportedOperationException if the {@code add} operation 83 * is not supported by this list 84 * @throws ClassCastException if the class of the specified element 85 * prevents it from being added to this list 86 * @throws NullPointerException if the specified element is null and this 87 * list does not permit null elements 88 * @throws IllegalArgumentException if some property of this element 89 * prevents it from being added to this list 90 */ 91 // bool add(E e) { throw new UnsupportedOperationException(""); } 92 93 /** 94 * {@inheritDoc} 95 * 96 * @throws IndexOutOfBoundsException {@inheritDoc} 97 */ 98 E get(int index) { 99 throw new UnsupportedOperationException(""); 100 } 101 102 E opIndex(int index) { 103 return get(index); 104 } 105 106 /** 107 * {@inheritDoc} 108 * 109 * <p>This implementation always throws an 110 * {@code UnsupportedOperationException}. 111 * 112 * @throws UnsupportedOperationException {@inheritDoc} 113 * @throws ClassCastException {@inheritDoc} 114 * @throws NullPointerException {@inheritDoc} 115 * @throws IllegalArgumentException {@inheritDoc} 116 * @throws IndexOutOfBoundsException {@inheritDoc} 117 */ 118 E set(int index, E element) { 119 throw new UnsupportedOperationException(""); 120 } 121 122 /** 123 * {@inheritDoc} 124 * 125 * <p>This implementation always throws an 126 * {@code UnsupportedOperationException}. 127 * 128 * @throws UnsupportedOperationException {@inheritDoc} 129 * @throws ClassCastException {@inheritDoc} 130 * @throws NullPointerException {@inheritDoc} 131 * @throws IllegalArgumentException {@inheritDoc} 132 * @throws IndexOutOfBoundsException {@inheritDoc} 133 */ 134 void add(int index, E element) { 135 throw new UnsupportedOperationException(""); 136 } 137 138 /** 139 * {@inheritDoc} 140 * 141 * <p>This implementation always throws an 142 * {@code UnsupportedOperationException}. 143 * 144 * @throws UnsupportedOperationException {@inheritDoc} 145 * @throws IndexOutOfBoundsException {@inheritDoc} 146 */ 147 E removeAt(int index) { 148 throw new UnsupportedOperationException(""); 149 } 150 151 // bool remove(E o) { throw new UnsupportedOperationException(""); } 152 153 // Search Operations 154 155 /** 156 * {@inheritDoc} 157 * 158 * <p>This implementation first gets a list iterator (with 159 * {@code listIterator()}). Then, it iterates over the list until the 160 * specified element is found or the end of the list is reached. 161 * 162 * @throws ClassCastException {@inheritDoc} 163 * @throws NullPointerException {@inheritDoc} 164 */ 165 int indexOf(E o) { 166 throw new UnsupportedOperationException(""); 167 } 168 169 /** 170 * {@inheritDoc} 171 * 172 * <p>This implementation first gets a list iterator that points to the end 173 * of the list (with {@code listIterator(size())}). Then, it iterates 174 * backwards over the list until the specified element is found, or the 175 * beginning of the list is reached. 176 * 177 * @throws ClassCastException {@inheritDoc} 178 * @throws NullPointerException {@inheritDoc} 179 */ 180 int lastIndexOf(E o) { 181 throw new UnsupportedOperationException(""); 182 } 183 184 // Bulk Operations 185 186 /** 187 * Removes all of the elements from this list (optional operation). 188 * The list will be empty after this call returns. 189 * 190 * <p>This implementation calls {@code removeRange(0, size())}. 191 * 192 * <p>Note that this implementation throws an 193 * {@code UnsupportedOperationException} unless {@code remove(int 194 * index)} or {@code removeRange(int fromIndex, int toIndex)} is 195 * overridden. 196 * 197 * @throws UnsupportedOperationException if the {@code clear} operation 198 * is not supported by this list 199 */ 200 // void clear() { throw new UnsupportedOperationException(""); } 201 202 // Comparison and hashing 203 204 /** 205 * Compares the specified object with this list for equality. Returns 206 * {@code true} if and only if the specified object is also a list, both 207 * lists have the same size, and all corresponding pairs of elements in 208 * the two lists are <i>equal</i>. (Two elements {@code e1} and 209 * {@code e2} are <i>equal</i> if {@code (e1==null ? e2==null : 210 * e1.equals(e2))}.) In other words, two lists are defined to be 211 * equal if they contain the same elements in the same order.<p> 212 * 213 * This implementation first checks if the specified object is this 214 * list. If so, it returns {@code true}; if not, it checks if the 215 * specified object is a list. If not, it returns {@code false}; if so, 216 * it iterates over both lists, comparing corresponding pairs of elements. 217 * If any comparison returns {@code false}, this method returns 218 * {@code false}. If either iterator runs out of elements before the 219 * other it returns {@code false} (as the lists are of unequal length); 220 * otherwise it returns {@code true} when the iterations complete. 221 * 222 * @param o the object to be compared for equality with this list 223 * @return {@code true} if the specified object is equal to this list 224 */ 225 override bool opEquals(Object o) { 226 if (o is this) 227 return true; 228 List!E e2 = cast(List!E) o; 229 if (e2 is null) 230 return false; 231 232 if (this.size() != e2.size()) 233 return false; 234 235 for (int i = 0; i < this.size(); i++) { 236 if (this.get(i) != e2.get(i)) 237 return false; 238 } 239 240 return true; 241 } 242 243 override bool opEquals(IObject o) { 244 return opEquals(cast(Object) o); 245 } 246 247 /** 248 * Returns the hash code value for this list. 249 * 250 * <p>This implementation uses exactly the code that is used to define the 251 * list hash function in the documentation for the {@link List#hashCode} 252 * method. 253 * 254 * @return the hash code value for this list 255 */ 256 override size_t toHash() @trusted nothrow { 257 size_t hashCode = 1; 258 try { 259 static if (is(E == class) || is(E == interface)) { 260 foreach (E e; this) { 261 hashCode = 31 * hashCode + (e is null ? 0 : (cast(Object) e).toHash()); 262 } 263 } else { 264 foreach (E e; this) 265 hashCode = 31 * hashCode + hashOf(e); 266 } 267 } catch (Exception e) { 268 hashCode = super.toHash(); 269 } 270 271 return hashCode; 272 } 273 274 override string toString() { 275 return super.toString(); 276 } 277 278 override int opApply(scope int delegate(ref E) dg) { 279 return 0; 280 } 281 282 283 static if (isOrderingComparable!E) { 284 void sort(bool isAscending = true) { 285 throw new UnsupportedOperationException(); 286 } 287 } 288 289 void sort(Comparator!E c) { 290 throw new UnsupportedOperationException(); 291 } 292 293 // List!(E) opCast(C)(C c) nothrow 294 // //if(is(C == immutable (E)[])) 295 // { 296 // return cast(List!(E))c; 297 // } 298 /** 299 * {@inheritDoc} 300 * 301 * <p>This implementation gets an iterator over the specified collection 302 * and iterates over it, inserting the elements obtained from the 303 * iterator into this list at the appropriate position, one at a time, 304 * using {@code add(int, E)}. 305 * Many implementations will override this method for efficiency. 306 * 307 * <p>Note that this implementation throws an 308 * {@code UnsupportedOperationException} unless 309 * {@link #add(int, Object) add(int, E)} is overridden. 310 * 311 * @throws UnsupportedOperationException {@inheritDoc} 312 * @throws ClassCastException {@inheritDoc} 313 * @throws NullPointerException {@inheritDoc} 314 * @throws IllegalArgumentException {@inheritDoc} 315 * @throws IndexOutOfBoundsException {@inheritDoc} 316 */ 317 // bool addAll(int index, Collection<E> c) { 318 // rangeCheckForAdd(index); 319 // bool modified = false; 320 // for (E e : c) { 321 // add(index++, e); 322 // modified = true; 323 // } 324 // return modified; 325 // } 326 } 327 328 329 /** 330 */ 331 class EmptyList(E) : AbstractList!E { 332 // private static long serialVersionUID = 8842843931221139166L; 333 334 override int size() { 335 return 0; 336 } 337 338 override bool isEmpty() { 339 return true; 340 } 341 342 override bool contains(E obj) { 343 return false; 344 } 345 // override bool containsAll(Collection!E c) { return c.isEmpty(); } 346 347 override E[] toArray() { 348 return new E[0]; 349 } 350 351 T[] toArray(T)(T[] a) { 352 if (a.length > 0) 353 a[0] = null; 354 return a; 355 } 356 357 override E get(int index) { 358 throw new IndexOutOfBoundsException("Index: " ~ index.to!string); 359 } 360 361 override bool add(E e) { 362 throw new UnsupportedOperationException(""); 363 } 364 365 override E removeAt(int index) { 366 throw new IndexOutOfBoundsException("Index: " ~ index.to!string); 367 } 368 369 override bool remove(E o) { 370 return false; 371 } 372 373 override int indexOf(E o) { 374 return -1; 375 } 376 377 override int lastIndexOf(E o) { 378 return -1; 379 } 380 381 override bool opEquals(Object o) { 382 return (typeid(o) == typeid(List!E)) && (cast(List!E) o).isEmpty(); 383 } 384 385 386 override size_t toHash() { 387 return 1; 388 } 389 390 // override 391 // bool removeIf(Predicate!E filter) { 392 // assert(filter !is null); 393 // return false; 394 // } 395 396 // override 397 // void replaceAll(UnaryOperator!E operator) { 398 // Objects.requireNonNull(operator); 399 // } 400 401 // Override default methods in Collection 402 override int opApply(scope int delegate(ref E) dg) { 403 return 0; 404 } 405 406 // override 407 // Spliterator!E spliterator() { return Spliterators.emptySpliterator(); } 408 409 // // Preserves singleton property 410 // private Object readResolve() { 411 // return EMPTY_LIST; 412 // } 413 }