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