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.util.Spliterator; 13 14 15 enum SpliteratorCharacteristic { 16 /** 17 * Characteristic value signifying that an encounter order is defined for 18 * elements. If so, this Spliterator guarantees that method 19 * {@link #trySplit} splits a strict prefix of elements, that method 20 * {@link #tryAdvance} steps by one element in prefix order, and that 21 * {@link #forEachRemaining} performs actions in encounter order. 22 * 23 * <p>A {@link Collection} has an encounter order if the corresponding 24 * {@link Collection#iterator} documents an order. If so, the encounter 25 * order is the same as the documented order. Otherwise, a collection does 26 * not have an encounter order. 27 * 28 * @apiNote Encounter order is guaranteed to be ascending index order for 29 * any {@link List}. But no order is guaranteed for hash-based collections 30 * such as {@link HashSet}. Clients of a Spliterator that reports 31 * {@code ORDERED} are expected to preserve ordering constraints in 32 * non-commutative parallel computations. 33 */ 34 ORDERED = 0x00000010, 35 36 /** 37 * Characteristic value signifying that, for each pair of 38 * encountered elements {@code x, y}, {@code !x.equals(y)}. This 39 * applies for example, to a Spliterator based on a {@link Set}. 40 */ 41 DISTINCT = 0x00000001, 42 43 /** 44 * Characteristic value signifying that encounter order follows a defined 45 * sort order. If so, method {@link #getComparator()} returns the associated 46 * Comparator, or {@code null} if all elements are {@link Comparable} and 47 * are sorted by their natural ordering. 48 * 49 * <p>A Spliterator that reports {@code SORTED} must also report 50 * {@code ORDERED}. 51 * 52 * @apiNote The spliterators for {@code Collection} classes in the JDK that 53 * implement {@link NavigableSet} or {@link SortedSet} report {@code SORTED}. 54 */ 55 SORTED = 0x00000004, 56 57 /** 58 * Characteristic value signifying that the value returned from 59 * {@code estimateSize()} prior to traversal or splitting represents a 60 * finite size that, in the absence of structural source modification, 61 * represents an exact count of the number of elements that would be 62 * encountered by a complete traversal. 63 * 64 * @apiNote Most Spliterators for Collections, that cover all elements of a 65 * {@code Collection} report this characteristic. Sub-spliterators, such as 66 * those for {@link HashSet}, that cover a sub-set of elements and 67 * approximate their reported size do not. 68 */ 69 SIZED = 0x00000040, 70 71 /** 72 * Characteristic value signifying that the source guarantees that 73 * encountered elements will not be {@code null}. (This applies, 74 * for example, to most concurrent collections, queues, and maps.) 75 */ 76 NONNULL = 0x00000100, 77 78 /** 79 * Characteristic value signifying that the element source cannot be 80 * structurally modified; that is, elements cannot be added, replaced, or 81 * removed, so such changes cannot occur during traversal. A Spliterator 82 * that does not report {@code IMMUTABLE} or {@code CONCURRENT} is expected 83 * to have a documented policy (for example throwing 84 * {@link ConcurrentModificationException}) concerning structural 85 * interference detected during traversal. 86 */ 87 IMMUTABLE = 0x00000400, 88 89 /** 90 * Characteristic value signifying that the element source may be safely 91 * concurrently modified (allowing additions, replacements, and/or removals) 92 * by multiple threads without external synchronization. If so, the 93 * Spliterator is expected to have a documented policy concerning the impact 94 * of modifications during traversal. 95 * 96 * <p>A top-level Spliterator should not report both {@code CONCURRENT} and 97 * {@code SIZED}, since the finite size, if known, may change if the source 98 * is concurrently modified during traversal. Such a Spliterator is 99 * inconsistent and no guarantees can be made about any computation using 100 * that Spliterator. Sub-spliterators may report {@code SIZED} if the 101 * sub-split size is known and additions or removals to the source are not 102 * reflected when traversing. 103 * 104 * @apiNote Most concurrent collections maintain a consistency policy 105 * guaranteeing accuracy with respect to elements present at the point of 106 * Spliterator construction, but possibly not reflecting subsequent 107 * additions or removals. 108 */ 109 CONCURRENT = 0x00001000, 110 111 /** 112 * Characteristic value signifying that all Spliterators resulting from 113 * {@code trySplit()} will be both {@link #SIZED} and {@link #SUBSIZED}. 114 * (This means that all child Spliterators, whether direct or indirect, will 115 * be {@code SIZED}.) 116 * 117 * <p>A Spliterator that does not report {@code SIZED} as required by 118 * {@code SUBSIZED} is inconsistent and no guarantees can be made about any 119 * computation using that Spliterator. 120 * 121 * @apiNote Some spliterators, such as the top-level spliterator for an 122 * approximately balanced binary tree, will report {@code SIZED} but not 123 * {@code SUBSIZED}, since it is common to know the size of the entire tree 124 * but not the exact sizes of subtrees. 125 */ 126 SUBSIZED = 0x00004000 127 } 128 129 /** 130 * An object for traversing and partitioning elements of a source. The source 131 * of elements covered by a Spliterator could be, for example, an array, a 132 * {@link Collection}, an IO channel, or a generator function. 133 * 134 * <p>A Spliterator may traverse elements individually ({@link 135 * #tryAdvance tryAdvance()}) or sequentially in bulk 136 * ({@link #forEachRemaining forEachRemaining()}). 137 * 138 * <p>A Spliterator may also partition off some of its elements (using 139 * {@link #trySplit}) as another Spliterator, to be used in 140 * possibly-parallel operations. Operations using a Spliterator that 141 * cannot split, or does so in a highly imbalanced or inefficient 142 * manner, are unlikely to benefit from parallelism. Traversal 143 * and splitting exhaust elements; each Spliterator is useful for only a single 144 * bulk computation. 145 * 146 * <p>A Spliterator also reports a set of {@link #characteristics()} of its 147 * structure, source, and elements from among {@link #ORDERED}, 148 * {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED}, {@link #NONNULL}, 149 * {@link #IMMUTABLE}, {@link #CONCURRENT}, and {@link #SUBSIZED}. These may 150 * be employed by Spliterator clients to control, specialize or simplify 151 * computation. For example, a Spliterator for a {@link Collection} would 152 * report {@code SIZED}, a Spliterator for a {@link Set} would report 153 * {@code DISTINCT}, and a Spliterator for a {@link SortedSet} would also 154 * report {@code SORTED}. Characteristics are reported as a simple unioned bit 155 * set. 156 * 157 * Some characteristics additionally constrain method behavior; for example if 158 * {@code ORDERED}, traversal methods must conform to their documented ordering. 159 * New characteristics may be defined in the future, so implementors should not 160 * assign meanings to unlisted values. 161 * 162 * <p><a name="binding">A Spliterator that does not report {@code IMMUTABLE} or 163 * {@code CONCURRENT} is expected to have a documented policy concerning: 164 * when the spliterator <em>binds</em> to the element source; and detection of 165 * structural interference of the element source detected after binding.</a> A 166 * <em>late-binding</em> Spliterator binds to the source of elements at the 167 * point of first traversal, first split, or first query for estimated size, 168 * rather than at the time the Spliterator is created. A Spliterator that is 169 * not <em>late-binding</em> binds to the source of elements at the point of 170 * construction or first invocation of any method. Modifications made to the 171 * source prior to binding are reflected when the Spliterator is traversed. 172 * After binding a Spliterator should, on a best-effort basis, throw 173 * {@link ConcurrentModificationException} if structural interference is 174 * detected. Spliterators that do this are called <em>fail-fast</em>. The 175 * bulk traversal method ({@link #forEachRemaining forEachRemaining()}) of a 176 * Spliterator may optimize traversal and check for structural interference 177 * after all elements have been traversed, rather than checking per-element and 178 * failing immediately. 179 * 180 * <p>Spliterators can provide an estimate of the number of remaining elements 181 * via the {@link #estimateSize} method. Ideally, as reflected in characteristic 182 * {@link #SIZED}, this value corresponds exactly to the number of elements 183 * that would be encountered in a successful traversal. However, even when not 184 * exactly known, an estimated value value may still be useful to operations 185 * being performed on the source, such as helping to determine whether it is 186 * preferable to split further or traverse the remaining elements sequentially. 187 * 188 * <p>Despite their obvious utility in parallel algorithms, spliterators are not 189 * expected to be thread-safe; instead, implementations of parallel algorithms 190 * using spliterators should ensure that the spliterator is only used by one 191 * thread at a time. This is generally easy to attain via <em>serial 192 * thread-confinement</em>, which often is a natural consequence of typical 193 * parallel algorithms that work by recursive decomposition. A thread calling 194 * {@link #trySplit()} may hand over the returned Spliterator to another thread, 195 * which in turn may traverse or further split that Spliterator. The behaviour 196 * of splitting and traversal is undefined if two or more threads operate 197 * concurrently on the same spliterator. If the original thread hands a 198 * spliterator off to another thread for processing, it is best if that handoff 199 * occurs before any elements are consumed with {@link #tryAdvance(Consumer) 200 * tryAdvance()}, as certain guarantees (such as the accuracy of 201 * {@link #estimateSize()} for {@code SIZED} spliterators) are only valid before 202 * traversal has begun. 203 * 204 * <p>Primitive subtype specializations of {@code Spliterator} are provided for 205 * {@link OfInt int}, {@link OfLong long}, and {@link OfDouble double} values. 206 * The subtype default implementations of 207 * {@link Spliterator#tryAdvance(hunt.util.functional.Consumer)} 208 * and {@link Spliterator#forEachRemaining(hunt.util.functional.Consumer)} box 209 * primitive values to instances of their corresponding wrapper class. Such 210 * boxing may undermine any performance advantages gained by using the primitive 211 * specializations. To avoid boxing, the corresponding primitive-based methods 212 * should be used. For example, 213 * {@link Spliterator.OfInt#tryAdvance(hunt.util.functional.IntConsumer)} 214 * and {@link Spliterator.OfInt#forEachRemaining(hunt.util.functional.IntConsumer)} 215 * should be used in preference to 216 * {@link Spliterator.OfInt#tryAdvance(hunt.util.functional.Consumer)} and 217 * {@link Spliterator.OfInt#forEachRemaining(hunt.util.functional.Consumer)}. 218 * Traversal of primitive values using boxing-based methods 219 * {@link #tryAdvance tryAdvance()} and 220 * {@link #forEachRemaining(hunt.util.functional.Consumer) forEachRemaining()} 221 * does not affect the order in which the values, transformed to boxed values, 222 * are encountered. 223 * 224 * @apiNote 225 * <p>Spliterators, like {@code Iterator}s, are for traversing the elements of 226 * a source. The {@code Spliterator} API was designed to support efficient 227 * parallel traversal in addition to sequential traversal, by supporting 228 * decomposition as well as single-element iteration. In addition, the 229 * protocol for accessing elements via a Spliterator is designed to impose 230 * smaller per-element overhead than {@code Iterator}, and to avoid the inherent 231 * race involved in having separate methods for {@code hasNext()} and 232 * {@code next()}. 233 * 234 * <p>For mutable sources, arbitrary and non-deterministic behavior may occur if 235 * the source is structurally interfered with (elements added, replaced, or 236 * removed) between the time that the Spliterator binds to its data source and 237 * the end of traversal. For example, such interference will produce arbitrary, 238 * non-deterministic results when using the {@code java.util.stream} framework. 239 * 240 * <p>Structural interference of a source can be managed in the following ways 241 * (in approximate order of decreasing desirability): 242 * <ul> 243 * <li>The source cannot be structurally interfered with. 244 * <br>For example, an instance of 245 * {@link hunt.concurrency.CopyOnWriteArrayList} is an immutable source. 246 * A Spliterator created from the source reports a characteristic of 247 * {@code IMMUTABLE}.</li> 248 * <li>The source manages concurrent modifications. 249 * <br>For example, a key set of a {@link hunt.concurrency.ConcurrentHashMap} 250 * is a concurrent source. A Spliterator created from the source reports a 251 * characteristic of {@code CONCURRENT}.</li> 252 * <li>The mutable source provides a late-binding and fail-fast Spliterator. 253 * <br>Late binding narrows the window during which interference can affect 254 * the calculation; fail-fast detects, on a best-effort basis, that structural 255 * interference has occurred after traversal has commenced and throws 256 * {@link ConcurrentModificationException}. For example, {@link ArrayList}, 257 * and many other non-concurrent {@code Collection} classes in the JDK, provide 258 * a late-binding, fail-fast spliterator.</li> 259 * <li>The mutable source provides a non-late-binding but fail-fast Spliterator. 260 * <br>The source increases the likelihood of throwing 261 * {@code ConcurrentModificationException} since the window of potential 262 * interference is larger.</li> 263 * <li>The mutable source provides a late-binding and non-fail-fast Spliterator. 264 * <br>The source risks arbitrary, non-deterministic behavior after traversal 265 * has commenced since interference is not detected. 266 * </li> 267 * <li>The mutable source provides a non-late-binding and non-fail-fast 268 * Spliterator. 269 * <br>The source increases the risk of arbitrary, non-deterministic behavior 270 * since non-detected interference may occur after construction. 271 * </li> 272 * </ul> 273 * 274 * <p><b>Example.</b> Here is a class (not a very useful one, except 275 * for illustration) that maintains an array in which the actual data 276 * are held in even locations, and unrelated tag data are held in odd 277 * locations. Its Spliterator ignores the tags. 278 * 279 * <pre> {@code 280 * class TaggedArray!(T) { 281 * private final Object[] elements; // immutable after construction 282 * TaggedArray(T[] data, Object[] tags) { 283 * int size = data.length; 284 * if (tags.length != size) throw new IllegalArgumentException(); 285 * this.elements = new Object[2 * size]; 286 * for (int i = 0, j = 0; i < size; ++i) { 287 * elements[j++] = data[i]; 288 * elements[j++] = tags[i]; 289 * } 290 * } 291 * 292 * public Spliterator!(T) spliterator() { 293 * return new TaggedArraySpliterator<>(elements, 0, elements.length); 294 * } 295 * 296 * static class TaggedArraySpliterator!(T) : Spliterator!(T) { 297 * private final Object[] array; 298 * private int origin; // current index, advanced on split or traversal 299 * private final int fence; // one past the greatest index 300 * 301 * TaggedArraySpliterator(Object[] array, int origin, int fence) { 302 * this.array = array; this.origin = origin; this.fence = fence; 303 * } 304 * 305 * public void forEachRemaining(Consumer!(T) action) { 306 * for (; origin < fence; origin += 2) 307 * action.accept((T) array[origin]); 308 * } 309 * 310 * public bool tryAdvance(Consumer!(T) action) { 311 * if (origin < fence) { 312 * action.accept((T) array[origin]); 313 * origin += 2; 314 * return true; 315 * } 316 * else // cannot advance 317 * return false; 318 * } 319 * 320 * public Spliterator!(T) trySplit() { 321 * int lo = origin; // divide range in half 322 * int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even 323 * if (lo < mid) { // split out left half 324 * origin = mid; // reset this Spliterator's origin 325 * return new TaggedArraySpliterator<>(array, lo, mid); 326 * } 327 * else // too small to split 328 * return null; 329 * } 330 * 331 * public long estimateSize() { 332 * return (long)((fence - origin) / 2); 333 * } 334 * 335 * public int characteristics() { 336 * return ORDERED | SIZED | IMMUTABLE | SUBSIZED; 337 * } 338 * } 339 * }}</pre> 340 * 341 * <p>As an example how a parallel computation framework, such as the 342 * {@code java.util.stream} package, would use Spliterator in a parallel 343 * computation, here is one way to implement an associated parallel forEach, 344 * that illustrates the primary usage idiom of splitting off subtasks until 345 * the estimated amount of work is small enough to perform 346 * sequentially. Here we assume that the order of processing across 347 * subtasks doesn't matter; different (forked) tasks may further split 348 * and process elements concurrently in undetermined order. This 349 * example uses a {@link hunt.concurrency.CountedCompleter}; 350 * similar usages apply to other parallel task constructions. 351 * 352 * <pre>{@code 353 * static !(T) void parEach(TaggedArray!(T) a, Consumer!(T) action) { 354 * Spliterator!(T) s = a.spliterator(); 355 * long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8); 356 * new ParEach(null, s, action, targetBatchSize).invoke(); 357 * } 358 * 359 * static class ParEach!(T) extends CountedCompleter!(void) { 360 * final Spliterator!(T) spliterator; 361 * final Consumer!(T) action; 362 * final long targetBatchSize; 363 * 364 * ParEach(ParEach!(T) parent, Spliterator!(T) spliterator, 365 * Consumer!(T) action, long targetBatchSize) { 366 * super(parent); 367 * this.spliterator = spliterator; this.action = action; 368 * this.targetBatchSize = targetBatchSize; 369 * } 370 * 371 * public void compute() { 372 * Spliterator!(T) sub; 373 * while (spliterator.estimateSize() > targetBatchSize && 374 * (sub = spliterator.trySplit()) !is null) { 375 * addToPendingCount(1); 376 * new ParEach<>(this, sub, action, targetBatchSize).fork(); 377 * } 378 * spliterator.forEachRemaining(action); 379 * propagateCompletion(); 380 * } 381 * }}</pre> 382 * 383 * @implNote 384 * If the bool system property {@code org.openjdk.java.util.stream.tripwire} 385 * is set to {@code true} then diagnostic warnings are reported if boxing of 386 * primitive values occur when operating on primitive subtype specializations. 387 * 388 * @param (T) the type of elements returned by this Spliterator 389 * 390 * @see Collection 391 * @since 1.8 392 */ 393 interface Spliterator(T) { 394 // /** 395 // * If a remaining element exists, performs the given action on it, 396 // * returning {@code true}; else returns {@code false}. If this 397 // * Spliterator is {@link #ORDERED} the action is performed on the 398 // * next element in encounter order. Exceptions thrown by the 399 // * action are relayed to the caller. 400 // * 401 // * @param action The action 402 // * @return {@code false} if no remaining elements existed 403 // * upon entry to this method, else {@code true}. 404 // * @throws NullPointerException if the specified action is null 405 // */ 406 // bool tryAdvance(Consumer!(T) action); 407 408 // /** 409 // * Performs the given action for each remaining element, sequentially in 410 // * the current thread, until all elements have been processed or the action 411 // * throws an exception. If this Spliterator is {@link #ORDERED}, actions 412 // * are performed in encounter order. Exceptions thrown by the action 413 // * are relayed to the caller. 414 // * 415 // * @implSpec 416 // * The default implementation repeatedly invokes {@link #tryAdvance} until 417 // * it returns {@code false}. It should be overridden whenever possible. 418 // * 419 // * @param action The action 420 // * @throws NullPointerException if the specified action is null 421 // */ 422 // default void forEachRemaining(Consumer!(T) action) { 423 // do { } while (tryAdvance(action)); 424 // } 425 426 // /** 427 // * If this spliterator can be partitioned, returns a Spliterator 428 // * covering elements, that will, upon return from this method, not 429 // * be covered by this Spliterator. 430 // * 431 // * <p>If this Spliterator is {@link #ORDERED}, the returned Spliterator 432 // * must cover a strict prefix of the elements. 433 // * 434 // * <p>Unless this Spliterator covers an infinite number of elements, 435 // * repeated calls to {@code trySplit()} must eventually return {@code null}. 436 // * Upon non-null return: 437 // * <ul> 438 // * <li>the value reported for {@code estimateSize()} before splitting, 439 // * must, after splitting, be greater than or equal to {@code estimateSize()} 440 // * for this and the returned Spliterator; and</li> 441 // * <li>if this Spliterator is {@code SUBSIZED}, then {@code estimateSize()} 442 // * for this spliterator before splitting must be equal to the sum of 443 // * {@code estimateSize()} for this and the returned Spliterator after 444 // * splitting.</li> 445 // * </ul> 446 // * 447 // * <p>This method may return {@code null} for any reason, 448 // * including emptiness, inability to split after traversal has 449 // * commenced, data structure constraints, and efficiency 450 // * considerations. 451 // * 452 // * @apiNote 453 // * An ideal {@code trySplit} method efficiently (without 454 // * traversal) divides its elements exactly in half, allowing 455 // * balanced parallel computation. Many departures from this ideal 456 // * remain highly effective; for example, only approximately 457 // * splitting an approximately balanced tree, or for a tree in 458 // * which leaf nodes may contain either one or two elements, 459 // * failing to further split these nodes. However, large 460 // * deviations in balance and/or overly inefficient {@code 461 // * trySplit} mechanics typically result in poor parallel 462 // * performance. 463 // * 464 // * @return a {@code Spliterator} covering some portion of the 465 // * elements, or {@code null} if this spliterator cannot be split 466 // */ 467 // Spliterator!(T) trySplit(); 468 469 // /** 470 // * Returns an estimate of the number of elements that would be 471 // * encountered by a {@link #forEachRemaining} traversal, or returns {@link 472 // * Long#MAX_VALUE} if infinite, unknown, or too expensive to compute. 473 // * 474 // * <p>If this Spliterator is {@link #SIZED} and has not yet been partially 475 // * traversed or split, or this Spliterator is {@link #SUBSIZED} and has 476 // * not yet been partially traversed, this estimate must be an accurate 477 // * count of elements that would be encountered by a complete traversal. 478 // * Otherwise, this estimate may be arbitrarily inaccurate, but must decrease 479 // * as specified across invocations of {@link #trySplit}. 480 // * 481 // * @apiNote 482 // * Even an inexact estimate is often useful and inexpensive to compute. 483 // * For example, a sub-spliterator of an approximately balanced binary tree 484 // * may return a value that estimates the number of elements to be half of 485 // * that of its parent; if the root Spliterator does not maintain an 486 // * accurate count, it could estimate size to be the power of two 487 // * corresponding to its maximum depth. 488 // * 489 // * @return the estimated size, or {@code Long.MAX_VALUE} if infinite, 490 // * unknown, or too expensive to compute. 491 // */ 492 // long estimateSize(); 493 494 // /** 495 // * Convenience method that returns {@link #estimateSize()} if this 496 // * Spliterator is {@link #SIZED}, else {@code -1}. 497 // * @implSpec 498 // * The default implementation returns the result of {@code estimateSize()} 499 // * if the Spliterator reports a characteristic of {@code SIZED}, and 500 // * {@code -1} otherwise. 501 // * 502 // * @return the exact size, if known, else {@code -1}. 503 // */ 504 // default long getExactSizeIfKnown() { 505 // return (characteristics() & SIZED) == 0 ? -1L : estimateSize(); 506 // } 507 508 // /** 509 // * Returns a set of characteristics of this Spliterator and its 510 // * elements. The result is represented as ORed values from {@link 511 // * #ORDERED}, {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED}, 512 // * {@link #NONNULL}, {@link #IMMUTABLE}, {@link #CONCURRENT}, 513 // * {@link #SUBSIZED}. Repeated calls to {@code characteristics()} on 514 // * a given spliterator, prior to or in-between calls to {@code trySplit}, 515 // * should always return the same result. 516 // * 517 // * <p>If a Spliterator reports an inconsistent set of 518 // * characteristics (either those returned from a single invocation 519 // * or across multiple invocations), no guarantees can be made 520 // * about any computation using this Spliterator. 521 // * 522 // * @apiNote The characteristics of a given spliterator before splitting 523 // * may differ from the characteristics after splitting. For specific 524 // * examples see the characteristic values {@link #SIZED}, {@link #SUBSIZED} 525 // * and {@link #CONCURRENT}. 526 // * 527 // * @return a representation of characteristics 528 // */ 529 // int characteristics(); 530 531 // /** 532 // * Returns {@code true} if this Spliterator's {@link 533 // * #characteristics} contain all of the given characteristics. 534 // * 535 // * @implSpec 536 // * The default implementation returns true if the corresponding bits 537 // * of the given characteristics are set. 538 // * 539 // * @param characteristics the characteristics to check for 540 // * @return {@code true} if all the specified characteristics are present, 541 // * else {@code false} 542 // */ 543 // default bool hasCharacteristics(int characteristics) { 544 // return (characteristics() & characteristics) == characteristics; 545 // } 546 547 // /** 548 // * If this Spliterator's source is {@link #SORTED} by a {@link Comparator}, 549 // * returns that {@code Comparator}. If the source is {@code SORTED} in 550 // * {@linkplain Comparable natural order}, returns {@code null}. Otherwise, 551 // * if the source is not {@code SORTED}, throws {@link IllegalStateException}. 552 // * 553 // * @implSpec 554 // * The default implementation always throws {@link IllegalStateException}. 555 // * 556 // * @return a Comparator, or {@code null} if the elements are sorted in the 557 // * natural order. 558 // * @throws IllegalStateException if the spliterator does not report 559 // * a characteristic of {@code SORTED}. 560 // */ 561 // default Comparator<T> getComparator() { 562 // throw new IllegalStateException(); 563 // } 564 565 566 567 // /** 568 // * A Spliterator specialized for primitive values. 569 // * 570 // * @param (T) the type of elements returned by this Spliterator. The 571 // * type must be a wrapper type for a primitive type, such as {@code Integer} 572 // * for the primitive {@code int} type. 573 // * @param <T_CONS> the type of primitive consumer. The type must be a 574 // * primitive specialization of {@link hunt.util.functional.Consumer} for 575 // * {@code T}, such as {@link hunt.util.functional.IntConsumer} for 576 // * {@code Integer}. 577 // * @param <T_SPLITR> the type of primitive Spliterator. The type must be 578 // * a primitive specialization of Spliterator for {@code T}, such as 579 // * {@link Spliterator.OfInt} for {@code Integer}. 580 // * 581 // * @see Spliterator.OfInt 582 // * @see Spliterator.OfLong 583 // * @see Spliterator.OfDouble 584 // * @since 1.8 585 // */ 586 // public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> 587 // extends Spliterator!(T) { 588 // @Override 589 // T_SPLITR trySplit(); 590 591 // /** 592 // * If a remaining element exists, performs the given action on it, 593 // * returning {@code true}; else returns {@code false}. If this 594 // * Spliterator is {@link #ORDERED} the action is performed on the 595 // * next element in encounter order. Exceptions thrown by the 596 // * action are relayed to the caller. 597 // * 598 // * @param action The action 599 // * @return {@code false} if no remaining elements existed 600 // * upon entry to this method, else {@code true}. 601 // * @throws NullPointerException if the specified action is null 602 // */ 603 // 604 // bool tryAdvance(T_CONS action); 605 606 // /** 607 // * Performs the given action for each remaining element, sequentially in 608 // * the current thread, until all elements have been processed or the 609 // * action throws an exception. If this Spliterator is {@link #ORDERED}, 610 // * actions are performed in encounter order. Exceptions thrown by the 611 // * action are relayed to the caller. 612 // * 613 // * @implSpec 614 // * The default implementation repeatedly invokes {@link #tryAdvance} 615 // * until it returns {@code false}. It should be overridden whenever 616 // * possible. 617 // * 618 // * @param action The action 619 // * @throws NullPointerException if the specified action is null 620 // */ 621 // 622 // default void forEachRemaining(T_CONS action) { 623 // do { } while (tryAdvance(action)); 624 // } 625 // } 626 627 // /** 628 // * A Spliterator specialized for {@code int} values. 629 // * @since 1.8 630 // */ 631 // public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> { 632 633 // @Override 634 // OfInt trySplit(); 635 636 // @Override 637 // bool tryAdvance(IntConsumer action); 638 639 // @Override 640 // default void forEachRemaining(IntConsumer action) { 641 // do { } while (tryAdvance(action)); 642 // } 643 644 // /** 645 // * {@inheritDoc} 646 // * @implSpec 647 // * If the action is an instance of {@code IntConsumer} then it is cast 648 // * to {@code IntConsumer} and passed to 649 // * {@link #tryAdvance(hunt.util.functional.IntConsumer)}; otherwise 650 // * the action is adapted to an instance of {@code IntConsumer}, by 651 // * boxing the argument of {@code IntConsumer}, and then passed to 652 // * {@link #tryAdvance(hunt.util.functional.IntConsumer)}. 653 // */ 654 // @Override 655 // default bool tryAdvance(Consumer<Integer> action) { 656 // if (action instanceof IntConsumer) { 657 // return tryAdvance((IntConsumer) action); 658 // } 659 // else { 660 // if (Tripwire.ENABLED) 661 // Tripwire.trip(getClass(), 662 // "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)"); 663 // return tryAdvance((IntConsumer) action::accept); 664 // } 665 // } 666 667 // /** 668 // * {@inheritDoc} 669 // * @implSpec 670 // * If the action is an instance of {@code IntConsumer} then it is cast 671 // * to {@code IntConsumer} and passed to 672 // * {@link #forEachRemaining(hunt.util.functional.IntConsumer)}; otherwise 673 // * the action is adapted to an instance of {@code IntConsumer}, by 674 // * boxing the argument of {@code IntConsumer}, and then passed to 675 // * {@link #forEachRemaining(hunt.util.functional.IntConsumer)}. 676 // */ 677 // @Override 678 // default void forEachRemaining(Consumer<Integer> action) { 679 // if (action instanceof IntConsumer) { 680 // forEachRemaining((IntConsumer) action); 681 // } 682 // else { 683 // if (Tripwire.ENABLED) 684 // Tripwire.trip(getClass(), 685 // "{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)"); 686 // forEachRemaining((IntConsumer) action::accept); 687 // } 688 // } 689 // } 690 691 // /** 692 // * A Spliterator specialized for {@code long} values. 693 // * @since 1.8 694 // */ 695 // public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> { 696 697 // @Override 698 // OfLong trySplit(); 699 700 // @Override 701 // bool tryAdvance(LongConsumer action); 702 703 // @Override 704 // default void forEachRemaining(LongConsumer action) { 705 // do { } while (tryAdvance(action)); 706 // } 707 708 // /** 709 // * {@inheritDoc} 710 // * @implSpec 711 // * If the action is an instance of {@code LongConsumer} then it is cast 712 // * to {@code LongConsumer} and passed to 713 // * {@link #tryAdvance(hunt.util.functional.LongConsumer)}; otherwise 714 // * the action is adapted to an instance of {@code LongConsumer}, by 715 // * boxing the argument of {@code LongConsumer}, and then passed to 716 // * {@link #tryAdvance(hunt.util.functional.LongConsumer)}. 717 // */ 718 // @Override 719 // default bool tryAdvance(Consumer<Long> action) { 720 // if (action instanceof LongConsumer) { 721 // return tryAdvance((LongConsumer) action); 722 // } 723 // else { 724 // if (Tripwire.ENABLED) 725 // Tripwire.trip(getClass(), 726 // "{0} calling Spliterator.OfLong.tryAdvance((LongConsumer) action::accept)"); 727 // return tryAdvance((LongConsumer) action::accept); 728 // } 729 // } 730 731 // /** 732 // * {@inheritDoc} 733 // * @implSpec 734 // * If the action is an instance of {@code LongConsumer} then it is cast 735 // * to {@code LongConsumer} and passed to 736 // * {@link #forEachRemaining(hunt.util.functional.LongConsumer)}; otherwise 737 // * the action is adapted to an instance of {@code LongConsumer}, by 738 // * boxing the argument of {@code LongConsumer}, and then passed to 739 // * {@link #forEachRemaining(hunt.util.functional.LongConsumer)}. 740 // */ 741 // @Override 742 // default void forEachRemaining(Consumer<Long> action) { 743 // if (action instanceof LongConsumer) { 744 // forEachRemaining((LongConsumer) action); 745 // } 746 // else { 747 // if (Tripwire.ENABLED) 748 // Tripwire.trip(getClass(), 749 // "{0} calling Spliterator.OfLong.forEachRemaining((LongConsumer) action::accept)"); 750 // forEachRemaining((LongConsumer) action::accept); 751 // } 752 // } 753 // } 754 755 // /** 756 // * A Spliterator specialized for {@code double} values. 757 // * @since 1.8 758 // */ 759 // public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> { 760 761 // @Override 762 // OfDouble trySplit(); 763 764 // @Override 765 // bool tryAdvance(DoubleConsumer action); 766 767 // @Override 768 // default void forEachRemaining(DoubleConsumer action) { 769 // do { } while (tryAdvance(action)); 770 // } 771 772 // /** 773 // * {@inheritDoc} 774 // * @implSpec 775 // * If the action is an instance of {@code DoubleConsumer} then it is 776 // * cast to {@code DoubleConsumer} and passed to 777 // * {@link #tryAdvance(hunt.util.functional.DoubleConsumer)}; otherwise 778 // * the action is adapted to an instance of {@code DoubleConsumer}, by 779 // * boxing the argument of {@code DoubleConsumer}, and then passed to 780 // * {@link #tryAdvance(hunt.util.functional.DoubleConsumer)}. 781 // */ 782 // @Override 783 // default bool tryAdvance(Consumer<Double> action) { 784 // if (action instanceof DoubleConsumer) { 785 // return tryAdvance((DoubleConsumer) action); 786 // } 787 // else { 788 // if (Tripwire.ENABLED) 789 // Tripwire.trip(getClass(), 790 // "{0} calling Spliterator.OfDouble.tryAdvance((DoubleConsumer) action::accept)"); 791 // return tryAdvance((DoubleConsumer) action::accept); 792 // } 793 // } 794 795 // /** 796 // * {@inheritDoc} 797 // * @implSpec 798 // * If the action is an instance of {@code DoubleConsumer} then it is 799 // * cast to {@code DoubleConsumer} and passed to 800 // * {@link #forEachRemaining(hunt.util.functional.DoubleConsumer)}; 801 // * otherwise the action is adapted to an instance of 802 // * {@code DoubleConsumer}, by boxing the argument of 803 // * {@code DoubleConsumer}, and then passed to 804 // * {@link #forEachRemaining(hunt.util.functional.DoubleConsumer)}. 805 // */ 806 // @Override 807 // default void forEachRemaining(Consumer<Double> action) { 808 // if (action instanceof DoubleConsumer) { 809 // forEachRemaining((DoubleConsumer) action); 810 // } 811 // else { 812 // if (Tripwire.ENABLED) 813 // Tripwire.trip(getClass(), 814 // "{0} calling Spliterator.OfDouble.forEachRemaining((DoubleConsumer) action::accept)"); 815 // forEachRemaining((DoubleConsumer) action::accept); 816 // } 817 // } 818 // } 819 }