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.Collections; 13 14 15 import hunt.collection.AbstractList; 16 import hunt.collection.AbstractMap; 17 import hunt.collection.AbstractSet; 18 import hunt.collection.Collection; 19 import hunt.collection.Enumeration; 20 import hunt.collection.List; 21 import hunt.collection.NavigableSet; 22 import hunt.collection.Map; 23 import hunt.collection.Set; 24 import hunt.collection.SortedSet; 25 import hunt.collection.TreeSet; 26 27 import hunt.Functions; 28 import hunt.Exceptions; 29 import hunt.Object; 30 31 import std.conv; 32 import std.range; 33 34 35 36 /** 37 */ 38 class Collections { 39 // Suppresses default constructor, ensuring non-instantiability. 40 41 private this() { 42 } 43 44 static Enumeration!T enumeration(T=string)(InputRange!T range) 45 { 46 return new RangeEnumeration!T(range); 47 } 48 49 static Enumeration!T enumeration(T=string)(T[] range) 50 { 51 return new RangeEnumeration!T(inputRangeObject(range)); 52 } 53 54 /** 55 * Returns true if the specified arguments are equal, or both null. 56 * 57 * NB: Do not replace with Object.equals until JDK-8015417 is resolved. 58 */ 59 // static bool eq(Object o1, Object o2) { 60 // return o1 is null ? o2 is null : o1.opEquals(o2); 61 // } 62 63 /** 64 * Returns an empty map (immutable). This map is serializable. 65 * 66 * !(p)This example illustrates the type-safe way to obtain an empty map: 67 * !(pre) 68 * Map<string, Date> s = Collections.emptyMap(); 69 * !(/pre) 70 * @implNote Implementations of this method need not create a separate 71 * {@code Map} object for each call. Using this method is likely to have 72 * comparable cost to using the like-named field. (Unlike this method, the 73 * field does not provide type safety.) 74 * 75 * @param (K) the class of the map keys 76 * @param (V) the class of the map values 77 * @return an empty map 78 * @see #EMPTY_MAP 79 */ 80 static Map!(K,V) emptyMap(K,V)() { 81 return new EmptyMap!(K,V)(); 82 } 83 84 /** 85 * Returns an empty navigable set (immutable). This set is serializable. 86 * 87 * <p>This example illustrates the type-safe way to obtain an empty 88 * navigable set: 89 * <pre> {@code 90 * NavigableSet!(string) s = Collections.emptyNavigableSet(); 91 * }</pre> 92 * 93 * @implNote Implementations of this method need not 94 * create a separate {@code NavigableSet} object for each call. 95 * 96 * @param !E type of elements, if there were any, in the set 97 * @return the empty navigable set 98 */ 99 static NavigableSet!(E) emptyNavigableSet(E)() { 100 return new EmptyNavigableSet!(E)(); 101 } 102 103 104 // Singleton collections 105 106 /** 107 * Returns an immutable set containing only the specified object. 108 * The returned set is serializable. 109 * 110 * @param !(T) the class of the objects in the set 111 * @param o the sole object to be stored in the returned set. 112 * @return an immutable set containing only the specified object. 113 */ 114 static Set!T singleton(T)(T o) { 115 return new SingletonSet!T(o); 116 } 117 118 119 /** 120 * Returns an immutable list containing only the specified object. 121 * The returned list is serializable. 122 * 123 * @param !(T) the class of the objects in the list 124 * @param o the sole object to be stored in the returned list. 125 * @return an immutable list containing only the specified object. 126 */ 127 static List!T singletonList(T)(T o) { 128 return new SingletonList!T(o); 129 } 130 131 static List!T emptyList(T)() 132 { 133 return new EmptyList!T(); 134 } 135 136 static Set!T emptySet(T)() { 137 return new EmptySet!T(); 138 } 139 140 } 141 142 143 144 private class SingletonSet(E) : AbstractSet!E 145 { 146 147 private E element; 148 149 this(E e) {element = e;} 150 151 override bool remove(E o) { 152 return true; 153 } 154 override 155 int size() {return 1;} 156 157 override bool contains(E)(E o) {return o == element;} 158 159 override 160 int opApply(scope int delegate(ref E) dg) { 161 dg(element); 162 return 0; 163 } 164 165 // Override default methods for Collection 166 // override 167 // void forEach(Consumer!E action) { 168 // action.accept(element); 169 // } 170 171 // override 172 // Spliterator!E spliterator() { 173 // return singletonSpliterator(element); 174 // } 175 176 override 177 bool removeIf(Predicate!E filter) { 178 throw new UnsupportedOperationException(); 179 } 180 } 181 182 183 /** 184 * @serial include 185 */ 186 private static class SingletonList(E) : AbstractList!E { 187 188 // private enum long serialVersionUID = 3093736618740652951L; 189 190 private E element; 191 192 this(E obj) {element = obj;} 193 194 // Iterator!E iterator() { 195 // return singletonIterator(element); 196 // } 197 198 override int size() {return 1;} 199 200 override bool contains(E obj) { 201 static if(is(E == class)) 202 return cast(Object)obj == cast(Object)element; 203 else 204 return element == obj; 205 } 206 207 override E get(int index) { 208 if (index != 0) 209 throw new IndexOutOfBoundsException("Index: " ~ index.to!string ~ ", Size: 1"); 210 return element; 211 } 212 213 // Override default methods for Collection 214 override 215 int opApply(scope int delegate(ref E) dg) 216 { 217 dg(element); 218 return 0; 219 } 220 221 // override 222 // boole removeIf(Predicate!E filter) { 223 // throw new UnsupportedOperationException(); 224 // } 225 // override 226 // void replaceAll(UnaryOperator!E operator) { 227 // throw new UnsupportedOperationException(); 228 // } 229 // override 230 // void sort(Comparator!(E) c) { 231 // } 232 // override 233 // Spliterator!E spliterator() { 234 // return singletonSpliterator(element); 235 // } 236 } 237 238 239 /** 240 * @serial include 241 */ 242 private class UnmodifiableCollection(E) : Collection!(E) { 243 // private static final long serialVersionUID = 1820017752578914078L; 244 245 protected Collection!(E) c; 246 247 this(Collection!(E) c) { 248 if (c is null) 249 throw new NullPointerException(); 250 this.c = c; 251 } 252 253 int size() {return c.size();} 254 bool isEmpty() {return c.isEmpty();} 255 bool contains(E o) {return c.contains(o);} 256 E[] toArray() {return c.toArray();} 257 // !(T) T[] toArray(T[] a) {return c.toArray(a);} 258 override string toString() {return c.toString();} 259 260 override size_t toHash() @trusted nothrow { return super.toHash(); } 261 262 InputRange!E iterator() { 263 throw new NotImplementedException(); 264 } 265 266 267 // Iterator!(E) iterator() { 268 // return new Iterator!(E)() { 269 // private final Iterator!(E) i = c.iterator(); 270 271 // bool hasNext() {return i.hasNext();} 272 // E next() {return i.next();} 273 // void remove() { 274 // throw new UnsupportedOperationException(); 275 // } 276 // override 277 // void forEachRemaining(Consumer!E action) { 278 // // Use backing collection version 279 // i.forEachRemaining(action); 280 // } 281 // }; 282 // } 283 284 bool add(E e) { 285 throw new UnsupportedOperationException(); 286 } 287 288 bool addAll(E[] e) { 289 throw new UnsupportedOperationException(); 290 } 291 292 bool remove(E o) { 293 throw new UnsupportedOperationException(); 294 } 295 296 bool containsAll(Collection!(E) coll) { 297 return c.containsAll(coll); 298 } 299 bool addAll(Collection!(E) coll) { 300 throw new UnsupportedOperationException(); 301 } 302 bool removeAll(Collection!(E) coll) { 303 throw new UnsupportedOperationException(); 304 } 305 bool retainAll(Collection!(E) coll) { 306 throw new UnsupportedOperationException(); 307 } 308 void clear() { 309 throw new UnsupportedOperationException(); 310 } 311 312 // Override default methods in Collection 313 // override 314 // void forEach(Consumer!(E) action) { 315 // c.forEach(action); 316 // } 317 int opApply(scope int delegate(ref E) dg) { 318 int r = 0; 319 foreach(E e; c) { 320 r = dg(e); 321 if(r != 0) return r; 322 } 323 return r; 324 } 325 326 override 327 bool removeIf(Predicate!(E) filter) { 328 throw new UnsupportedOperationException(); 329 } 330 331 bool opEquals(IObject o) { 332 return opEquals(cast(Object) o); 333 } 334 335 alias opEquals = Object.opEquals; 336 337 // override 338 // Spliterator!(E) spliterator() { 339 // return (Spliterator!(E))c.spliterator(); 340 // } 341 342 // override 343 // Stream!(E) stream() { 344 // return (Stream!(E))c.stream(); 345 // } 346 347 // override 348 // Stream!(E) parallelStream() { 349 // return (Stream!(E))c.parallelStream(); 350 // } 351 } 352 353 /** 354 * @serial include 355 */ 356 private class UnmodifiableSet(E) : UnmodifiableCollection!(E), Set!(E) { 357 // private static final long serialVersionUID = -9215047833775013803L; 358 359 this(Set!(E) s) {super(s);} 360 override bool opEquals(Object o) {return o is this || c == o;} 361 362 override bool opEquals(IObject o) { 363 return opEquals(cast(Object) o); 364 } 365 366 override string toString() { 367 return super.toString(); 368 } 369 370 override size_t toHash() @trusted nothrow { return c.toHash();} 371 } 372 373 /** 374 * A singleton empty unmodifiable navigable set used for 375 * {@link #emptyNavigableSet()}. 376 * 377 * @param (E) type of elements, if there were any, and bounds 378 */ 379 private class EmptyNavigableSet(E) : UnmodifiableNavigableSet!(E) { 380 // private static final long serialVersionUID = -6291252904449939134L; 381 382 this() { 383 super(new TreeSet!(E)()); 384 } 385 386 // private Object readResolve() { return EMPTY_NAVIGABLE_SET; } 387 } 388 389 /** 390 * @serial include 391 */ 392 private class UnmodifiableSortedSet(E) : UnmodifiableSet!(E), SortedSet!(E) { 393 // private static final long serialVersionUID = -4929149591599911165L; 394 private SortedSet!(E) ss; 395 396 this(SortedSet!(E) s) {super(s); ss = s;} 397 398 // Comparator!E comparator() {return ss.comparator();} 399 400 SortedSet!(E) subSet(E fromElement, E toElement) { 401 return new UnmodifiableSortedSet!(E)(ss.subSet(fromElement,toElement)); 402 } 403 SortedSet!(E) headSet(E toElement) { 404 return new UnmodifiableSortedSet!(E)(ss.headSet(toElement)); 405 } 406 SortedSet!(E) tailSet(E fromElement) { 407 return new UnmodifiableSortedSet!(E)(ss.tailSet(fromElement)); 408 } 409 410 E first() {return ss.first();} 411 E last() {return ss.last();} 412 413 414 override bool opEquals(IObject o) { 415 return opEquals(cast(Object) o); 416 } 417 418 alias opEquals = Object.opEquals; 419 420 override string toString() { 421 return super.toString(); 422 } 423 424 override size_t toHash() @trusted nothrow { 425 return super.toHash(); 426 } 427 428 } 429 430 431 /** 432 * Wraps a navigable set and disables all of the mutative operations. 433 * 434 * @param (E) type of elements 435 * @serial include 436 */ 437 private class UnmodifiableNavigableSet(E) : 438 UnmodifiableSortedSet!(E), NavigableSet!(E) { 439 440 /** 441 * The instance we are protecting. 442 */ 443 private NavigableSet!(E) ns; 444 445 this(NavigableSet!(E) s) {super(s); ns = s;} 446 447 E lower(E e) { return ns.lower(e); } 448 E floor(E e) { return ns.floor(e); } 449 E ceiling(E e) { return ns.ceiling(e); } 450 E higher(E e) { return ns.higher(e); } 451 E pollFirst() { throw new UnsupportedOperationException(); } 452 E pollLast() { throw new UnsupportedOperationException(); } 453 // NavigableSet!(E) descendingSet() 454 // { return new UnmodifiableNavigableSet!(E)(ns.descendingSet()); } 455 // Iterator!(E) descendingIterator() 456 // { return descendingSet().iterator(); } 457 458 NavigableSet!(E) subSet(E fromElement, bool fromInclusive, E toElement, bool toInclusive) { 459 return new UnmodifiableNavigableSet!(E)( 460 ns.subSet(fromElement, fromInclusive, toElement, toInclusive)); 461 } 462 463 NavigableSet!(E) headSet(E toElement, bool inclusive) { 464 return new UnmodifiableNavigableSet!(E)( 465 ns.headSet(toElement, inclusive)); 466 } 467 468 NavigableSet!(E) tailSet(E fromElement, bool inclusive) { 469 return new UnmodifiableNavigableSet!(E)( 470 ns.tailSet(fromElement, inclusive)); 471 } 472 473 override SortedSet!(E) subSet(E fromElement, E toElement) { 474 return new UnmodifiableSortedSet!(E)(ss.subSet(fromElement,toElement)); 475 } 476 override SortedSet!(E) headSet(E toElement) { 477 return new UnmodifiableSortedSet!(E)(ss.headSet(toElement)); 478 } 479 override SortedSet!(E) tailSet(E fromElement) { 480 return new UnmodifiableSortedSet!(E)(ss.tailSet(fromElement)); 481 } 482 483 // alias subSet = UnmodifiableSortedSet!(E).subSet; 484 // alias headSet = UnmodifiableSortedSet!(E).headSet; 485 // alias tailSet = UnmodifiableSortedSet!(E).tailSet; 486 487 override bool opEquals(IObject o) { 488 return opEquals(cast(Object) o); 489 } 490 491 alias opEquals = Object.opEquals; 492 493 override string toString() { 494 return super.toString(); 495 } 496 497 override size_t toHash() @trusted nothrow { 498 return super.toHash(); 499 } 500 501 // alias toString = Object.toString; 502 // alias toHash = Object.toHash; 503 504 }