1 /* 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package java.util.stream; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.Iterator; 30 import java.util.List; 31 import java.util.PrimitiveIterator; 32 import java.util.Spliterator; 33 import java.util.Spliterators; 34 import java.util.function.Consumer; 35 import java.util.function.DoubleConsumer; 36 import java.util.function.IntConsumer; 37 import java.util.function.IntFunction; 38 import java.util.function.LongConsumer; 39 40 /** 41 * An ordered collection of elements. Elements can be added, but not removed. 42 * Goes through a building phase, during which elements can be added, and a 43 * traversal phase, during which elements can be traversed in order but no 44 * further modifications are possible. 45 * 46 * <p> One or more arrays are used to store elements. The use of a multiple 47 * arrays has better performance characteristics than a single array used by 48 * {@link ArrayList}, as when the capacity of the list needs to be increased 49 * no copying of elements is required. This is usually beneficial in the case 50 * where the results will be traversed a small number of times. 51 * </p> 52 * 53 * @param <E> the type of elements in this list 54 * @since 1.8 55 */ 56 class SpinedBuffer<E> 57 extends AbstractSpinedBuffer 58 implements Consumer<E>, Iterable<E> { 59 60 /* 61 * We optimistically hope that all the data will fit into the first chunk, 62 * so we try to avoid inflating the spine[] and priorElementCount[] arrays 63 * prematurely. So methods must be prepared to deal with these arrays being 64 * null. If spine is non-null, then spineIndex points to the current chunk 65 * within the spine, otherwise it is zero. The spine and priorElementCount 66 * arrays are always the same size, and for any i <= spineIndex, 67 * priorElementCount[i] is the sum of the sizes of all the prior chunks. 68 * 69 * The curChunk pointer is always valid. The elementIndex is the index of 70 * the next element to be written in curChunk; this may be past the end of 71 * curChunk so we have to check before writing. When we inflate the spine 72 * array, curChunk becomes the first element in it. When we clear the 73 * buffer, we discard all chunks except the first one, which we clear, 74 * restoring it to the initial single-chunk state. 75 * 76 */ 77 78 /** 79 * Chunk that we're currently writing into; may or may not be aliased with 80 * the first element of the spine 81 */ 82 protected E[] curChunk; 83 84 /** All chunks, or null if there is only one chunk */ 85 protected E[][] spine; 86 87 /** 88 * Constructs an empty list with the specified initial capacity. 89 * 90 * @param initialCapacity the initial capacity of the list 91 * @throws IllegalArgumentException if the specified initial capacity 92 * is negative 93 */ 94 SpinedBuffer(int initialCapacity) { 95 super(initialCapacity); 96 curChunk = (E[]) new Object[1 << initialChunkPower]; 97 } 98 99 /** 100 * Constructs an empty list with an initial capacity of sixteen. 101 */ 102 SpinedBuffer() { 103 super(); 104 curChunk = (E[]) new Object[1 << initialChunkPower]; 105 } 106 107 /** Returns the current capacity of the buffer */ 108 protected long capacity() { 109 return (spineIndex == 0) 110 ? curChunk.length 111 : priorElementCount[spineIndex] + spine[spineIndex].length; 112 } 113 114 private void inflateSpine() { 115 if (spine == null) { 116 spine = (E[][]) new Object[MIN_SPINE_SIZE][]; 117 priorElementCount = new long[MIN_SPINE_SIZE]; 118 spine[0] = curChunk; 119 } 120 } 121 122 /** Ensure that the buffer has at least capacity to hold the target size */ 123 protected final void ensureCapacity(long targetSize) { 124 long capacity = capacity(); 125 if (targetSize > capacity) { 126 inflateSpine(); 127 for (int i=spineIndex+1; targetSize > capacity; i++) { 128 if (i >= spine.length) { 129 int newSpineSize = spine.length * 2; 130 spine = Arrays.copyOf(spine, newSpineSize); 131 priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize); 132 } 133 int nextChunkSize = chunkSize(i); 134 spine[i] = (E[]) new Object[nextChunkSize]; 135 priorElementCount[i] = priorElementCount[i-1] + spine[i-1].length; 136 capacity += nextChunkSize; 137 } 138 } 139 } 140 141 /** Force the buffer to increase its capacity */ 142 protected void increaseCapacity() { 143 ensureCapacity(capacity() + 1); 144 } 145 146 /** Retrieve the element at the specified index */ 147 public E get(long index) { 148 // @@@ can further optimize by caching last seen spineIndex, 149 // which is going to be right most of the time 150 if (spineIndex == 0) { 151 if (index < elementIndex) 152 return curChunk[((int) index)]; 153 else 154 throw new IndexOutOfBoundsException(Long.toString(index)); 155 } 156 157 if (index >= count()) 158 throw new IndexOutOfBoundsException(Long.toString(index)); 159 160 for (int j=0; j <= spineIndex; j++) 161 if (index < priorElementCount[j] + spine[j].length) 162 return spine[j][((int) (index - priorElementCount[j]))]; 163 164 throw new IndexOutOfBoundsException(Long.toString(index)); 165 } 166 167 /** Copy the elements, starting at the specified offset, into the specified array */ 168 public void copyInto(E[] array, int offset) { 169 long finalOffset = offset + count(); 170 if (finalOffset > array.length || finalOffset < offset) { 171 throw new IndexOutOfBoundsException("does not fit"); 172 } 173 174 if (spineIndex == 0) 175 System.arraycopy(curChunk, 0, array, offset, elementIndex); 176 else { 177 // full chunks 178 for (int i=0; i < spineIndex; i++) { 179 System.arraycopy(spine[i], 0, array, offset, spine[i].length); 180 offset += spine[i].length; 181 } 182 if (elementIndex > 0) 183 System.arraycopy(curChunk, 0, array, offset, elementIndex); 184 } 185 } 186 187 /** Create a new array using the specified array factory, and copy the elements into it */ 188 public E[] asArray(IntFunction<E[]> arrayFactory) { 189 // @@@ will fail for size == MAX_VALUE 190 E[] result = arrayFactory.apply((int) count()); 191 192 copyInto(result, 0); 193 194 return result; 195 } 196 197 @Override 198 public void clear() { 199 if (spine != null) { 200 curChunk = spine[0]; 201 for (int i=0; i<curChunk.length; i++) 202 curChunk[i] = null; 203 spine = null; 204 priorElementCount = null; 205 } 206 else { 207 for (int i=0; i<elementIndex; i++) 208 curChunk[i] = null; 209 } 210 elementIndex = 0; 211 spineIndex = 0; 212 } 213 214 @Override 215 public Iterator<E> iterator() { 216 return Spliterators.iteratorFromSpliterator(spliterator()); 217 } 218 219 @Override 220 public void forEach(Consumer<? super E> consumer) { 221 // completed chunks, if any 222 for (int j = 0; j < spineIndex; j++) 223 for (E t : spine[j]) 224 consumer.accept(t); 225 226 // current chunk 227 for (int i=0; i<elementIndex; i++) 228 consumer.accept(curChunk[i]); 229 } 230 231 @Override 232 public void accept(E e) { 233 if (elementIndex == curChunk.length) { 234 inflateSpine(); 235 if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null) 236 increaseCapacity(); 237 elementIndex = 0; 238 ++spineIndex; 239 curChunk = spine[spineIndex]; 240 } 241 curChunk[elementIndex++] = e; 242 } 243 244 @Override 245 public String toString() { 246 List<E> list = new ArrayList<>(); 247 forEach(list::add); 248 return "SpinedBuffer:" + list.toString(); 249 } 250 251 private static final int SPLITERATOR_CHARACTERISTICS 252 = Spliterator.SIZED | Spliterator.ORDERED | Spliterator.SUBSIZED; 253 254 /** Return a {@link Spliterator} describing the contents of the buffer */ 255 public Spliterator<E> spliterator() { 256 return new Spliterator<E>() { 257 // The current spine index 258 int splSpineIndex; 259 260 // The current element index into the current spine 261 int splElementIndex; 262 263 // When splSpineIndex >= spineIndex and splElementIndex >= elementIndex then 264 // this spliterator is fully traversed 265 // tryAdvance can set splSpineIndex > spineIndex if the last spine is full 266 267 // The current spine array 268 E[] splChunk = (spine == null) ? curChunk : spine[0]; 269 270 @Override 271 public long estimateSize() { 272 return (spine == null) 273 ? (elementIndex - splElementIndex) 274 : count() - (priorElementCount[splSpineIndex] + splElementIndex); 275 } 276 277 @Override 278 public int characteristics() { 279 return SPLITERATOR_CHARACTERISTICS; 280 } 281 282 @Override 283 public boolean tryAdvance(Consumer<? super E> consumer) { 284 if (splSpineIndex < spineIndex 285 || (splSpineIndex == spineIndex && splElementIndex < elementIndex)) { 286 consumer.accept(splChunk[splElementIndex++]); 287 288 if (splElementIndex == splChunk.length) { 289 splElementIndex = 0; 290 ++splSpineIndex; 291 if (spine != null && splSpineIndex < spine.length) 292 splChunk = spine[splSpineIndex]; 293 } 294 return true; 295 } 296 return false; 297 } 298 299 @Override 300 public void forEachRemaining(Consumer<? super E> consumer) { 301 if (splSpineIndex < spineIndex 302 || (splSpineIndex == spineIndex && splElementIndex < elementIndex)) { 303 int i = splElementIndex; 304 // completed chunks, if any 305 for (int sp = splSpineIndex; sp < spineIndex; sp++) { 306 E[] chunk = spine[sp]; 307 for (; i < chunk.length; i++) { 308 consumer.accept(chunk[i]); 309 } 310 i = 0; 311 } 312 313 // current chunk 314 E[] chunk = curChunk; 315 int hElementIndex = elementIndex; 316 for (; i < hElementIndex; i++) { 317 consumer.accept(chunk[i]); 318 } 319 320 splSpineIndex = spineIndex; 321 splElementIndex = elementIndex; 322 } 323 } 324 325 @Override 326 public Spliterator<E> trySplit() { 327 if (splSpineIndex < spineIndex) { 328 Spliterator<E> ret = Arrays.spliterator(spine[splSpineIndex], 329 splElementIndex, spine[splSpineIndex].length); 330 splChunk = spine[++splSpineIndex]; 331 splElementIndex = 0; 332 return ret; 333 } 334 else if (splSpineIndex == spineIndex) { 335 int t = (elementIndex - splElementIndex) / 2; 336 if (t == 0) 337 return null; 338 else { 339 Spliterator<E> ret = Arrays.spliterator(curChunk, splElementIndex, splElementIndex + t); 340 splElementIndex += t; 341 return ret; 342 } 343 } 344 else { 345 return null; 346 } 347 } 348 }; 349 } 350 351 /** 352 * An ordered collection of primitive values. Elements can be added, but 353 * not removed. Goes through a building phase, during which elements can be 354 * added, and a traversal phase, during which elements can be traversed in 355 * order but no further modifications are possible. 356 * 357 * <p> One or more arrays are used to store elements. The use of a multiple 358 * arrays has better performance characteristics than a single array used by 359 * {@link ArrayList}, as when the capacity of the list needs to be increased 360 * no copying of elements is required. This is usually beneficial in the case 361 * where the results will be traversed a small number of times. 362 * 363 * @param <E> the wrapper type for this primitive type 364 * @param <T_ARR> the array type for this primitive type 365 * @param <T_CONS> the Consumer type for this primitive type 366 */ 367 abstract static class OfPrimitive<E, T_ARR, T_CONS> 368 extends AbstractSpinedBuffer implements Iterable<E> { 369 370 /* 371 * We optimistically hope that all the data will fit into the first chunk, 372 * so we try to avoid inflating the spine[] and priorElementCount[] arrays 373 * prematurely. So methods must be prepared to deal with these arrays being 374 * null. If spine is non-null, then spineIndex points to the current chunk 375 * within the spine, otherwise it is zero. The spine and priorElementCount 376 * arrays are always the same size, and for any i <= spineIndex, 377 * priorElementCount[i] is the sum of the sizes of all the prior chunks. 378 * 379 * The curChunk pointer is always valid. The elementIndex is the index of 380 * the next element to be written in curChunk; this may be past the end of 381 * curChunk so we have to check before writing. When we inflate the spine 382 * array, curChunk becomes the first element in it. When we clear the 383 * buffer, we discard all chunks except the first one, which we clear, 384 * restoring it to the initial single-chunk state. 385 */ 386 387 // The chunk we're currently writing into 388 T_ARR curChunk; 389 390 // All chunks, or null if there is only one chunk 391 T_ARR[] spine; 392 393 /** 394 * Constructs an empty list with the specified initial capacity. 395 * 396 * @param initialCapacity the initial capacity of the list 397 * @throws IllegalArgumentException if the specified initial capacity 398 * is negative 399 */ 400 OfPrimitive(int initialCapacity) { 401 super(initialCapacity); 402 curChunk = newArray(1 << initialChunkPower); 403 } 404 405 /** 406 * Constructs an empty list with an initial capacity of sixteen. 407 */ 408 OfPrimitive() { 409 super(); 410 curChunk = newArray(1 << initialChunkPower); 411 } 412 413 @Override 414 public abstract Iterator<E> iterator(); 415 416 @Override 417 public abstract void forEach(Consumer<? super E> consumer); 418 419 /** Create a new array-of-array of the proper type and size */ 420 protected abstract T_ARR[] newArrayArray(int size); 421 422 /** Create a new array of the proper type and size */ 423 protected abstract T_ARR newArray(int size); 424 425 /** Get the length of an array */ 426 protected abstract int arrayLength(T_ARR array); 427 428 /** Iterate an array with the provided consumer */ 429 protected abstract void arrayForEach(T_ARR array, int from, int to, 430 T_CONS consumer); 431 432 protected long capacity() { 433 return (spineIndex == 0) 434 ? arrayLength(curChunk) 435 : priorElementCount[spineIndex] + arrayLength(spine[spineIndex]); 436 } 437 438 private void inflateSpine() { 439 if (spine == null) { 440 spine = newArrayArray(MIN_SPINE_SIZE); 441 priorElementCount = new long[MIN_SPINE_SIZE]; 442 spine[0] = curChunk; 443 } 444 } 445 446 protected final void ensureCapacity(long targetSize) { 447 long capacity = capacity(); 448 if (targetSize > capacity) { 449 inflateSpine(); 450 for (int i=spineIndex+1; targetSize > capacity; i++) { 451 if (i >= spine.length) { 452 int newSpineSize = spine.length * 2; 453 spine = Arrays.copyOf(spine, newSpineSize); 454 priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize); 455 } 456 int nextChunkSize = chunkSize(i); 457 spine[i] = newArray(nextChunkSize); 458 priorElementCount[i] = priorElementCount[i-1] + arrayLength(spine[i - 1]); 459 capacity += nextChunkSize; 460 } 461 } 462 } 463 464 protected void increaseCapacity() { 465 ensureCapacity(capacity() + 1); 466 } 467 468 protected int chunkFor(long index) { 469 if (spineIndex == 0) { 470 if (index < elementIndex) 471 return 0; 472 else 473 throw new IndexOutOfBoundsException(Long.toString(index)); 474 } 475 476 if (index >= count()) 477 throw new IndexOutOfBoundsException(Long.toString(index)); 478 479 for (int j=0; j <= spineIndex; j++) 480 if (index < priorElementCount[j] + arrayLength(spine[j])) 481 return j; 482 483 throw new IndexOutOfBoundsException(Long.toString(index)); 484 } 485 486 public void copyInto(T_ARR array, int offset) { 487 long finalOffset = offset + count(); 488 if (finalOffset > arrayLength(array) || finalOffset < offset) { 489 throw new IndexOutOfBoundsException("does not fit"); 490 } 491 492 if (spineIndex == 0) 493 System.arraycopy(curChunk, 0, array, offset, elementIndex); 494 else { 495 // full chunks 496 for (int i=0; i < spineIndex; i++) { 497 System.arraycopy(spine[i], 0, array, offset, arrayLength(spine[i])); 498 offset += arrayLength(spine[i]); 499 } 500 if (elementIndex > 0) 501 System.arraycopy(curChunk, 0, array, offset, elementIndex); 502 } 503 } 504 505 public T_ARR asPrimitiveArray() { 506 // @@@ will fail for size == MAX_VALUE 507 T_ARR result = newArray((int) count()); 508 copyInto(result, 0); 509 return result; 510 } 511 512 protected void preAccept() { 513 if (elementIndex == arrayLength(curChunk)) { 514 inflateSpine(); 515 if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null) 516 increaseCapacity(); 517 elementIndex = 0; 518 ++spineIndex; 519 curChunk = spine[spineIndex]; 520 } 521 } 522 523 public void clear() { 524 if (spine != null) { 525 curChunk = spine[0]; 526 spine = null; 527 priorElementCount = null; 528 } 529 elementIndex = 0; 530 spineIndex = 0; 531 } 532 533 public void forEach(T_CONS consumer) { 534 // completed chunks, if any 535 for (int j = 0; j < spineIndex; j++) 536 arrayForEach(spine[j], 0, arrayLength(spine[j]), consumer); 537 538 // current chunk 539 arrayForEach(curChunk, 0, elementIndex, consumer); 540 } 541 542 abstract class BaseSpliterator<T_SPLITER extends Spliterator<E>> 543 implements Spliterator<E> { 544 // The current spine index 545 int splSpineIndex; 546 547 // The current element index into the current spine 548 int splElementIndex; 549 550 // When splSpineIndex >= spineIndex and splElementIndex >= elementIndex then 551 // this spliterator is fully traversed 552 // tryAdvance can set splSpineIndex > spineIndex if the last spine is full 553 554 // The current spine array 555 T_ARR splChunk = (spine == null) ? curChunk : spine[0]; 556 557 abstract void arrayForOne(T_ARR array, int index, T_CONS consumer); 558 559 abstract T_SPLITER arraySpliterator(T_ARR array, int offset, int len); 560 561 @Override 562 public long estimateSize() { 563 return (spine == null) 564 ? (elementIndex - splElementIndex) 565 : count() - (priorElementCount[splSpineIndex] + splElementIndex); 566 } 567 568 @Override 569 public int characteristics() { 570 return SPLITERATOR_CHARACTERISTICS; 571 } 572 573 public boolean tryAdvance(T_CONS consumer) { 574 if (splSpineIndex < spineIndex 575 || (splSpineIndex == spineIndex && splElementIndex < elementIndex)) { 576 arrayForOne(splChunk, splElementIndex++, consumer); 577 578 if (splElementIndex == arrayLength(splChunk)) { 579 splElementIndex = 0; 580 ++splSpineIndex; 581 if (spine != null && splSpineIndex < spine.length) 582 splChunk = spine[splSpineIndex]; 583 } 584 return true; 585 } 586 return false; 587 } 588 589 public void forEachRemaining(T_CONS consumer) { 590 if (splSpineIndex < spineIndex 591 || (splSpineIndex == spineIndex && splElementIndex < elementIndex)) { 592 int i = splElementIndex; 593 // completed chunks, if any 594 for (int sp = splSpineIndex; sp < spineIndex; sp++) { 595 T_ARR chunk = spine[sp]; 596 arrayForEach(chunk, i, arrayLength(chunk), consumer); 597 i = 0; 598 } 599 600 arrayForEach(curChunk, i, elementIndex, consumer); 601 602 splSpineIndex = spineIndex; 603 splElementIndex = elementIndex; 604 } 605 } 606 607 @Override 608 public T_SPLITER trySplit() { 609 if (splSpineIndex < spineIndex) { 610 T_SPLITER ret = arraySpliterator(spine[splSpineIndex], splElementIndex, 611 arrayLength(spine[splSpineIndex]) - splElementIndex); 612 splChunk = spine[++splSpineIndex]; 613 splElementIndex = 0; 614 return ret; 615 } 616 else if (splSpineIndex == spineIndex) { 617 int t = (elementIndex - splElementIndex) / 2; 618 if (t == 0) 619 return null; 620 else { 621 T_SPLITER ret = arraySpliterator(curChunk, splElementIndex, t); 622 splElementIndex += t; 623 return ret; 624 } 625 } 626 else { 627 return null; 628 } 629 } 630 } 631 } 632 633 /** 634 * An ordered collection of {@code int} values. 635 */ 636 static class OfInt extends SpinedBuffer.OfPrimitive<Integer, int[], IntConsumer> 637 implements IntConsumer { 638 OfInt() { } 639 640 OfInt(int initialCapacity) { 641 super(initialCapacity); 642 } 643 644 @Override 645 public void forEach(Consumer<? super Integer> consumer) { 646 if (consumer instanceof IntConsumer) { 647 forEach((IntConsumer) consumer); 648 } 649 else { 650 if (Tripwire.ENABLED) 651 Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfInt.forEach(Consumer)"); 652 spliterator().forEachRemaining(consumer); 653 } 654 } 655 656 @Override 657 protected int[][] newArrayArray(int size) { 658 return new int[size][]; 659 } 660 661 @Override 662 protected int[] newArray(int size) { 663 return new int[size]; 664 } 665 666 @Override 667 protected int arrayLength(int[] array) { 668 return array.length; 669 } 670 671 @Override 672 protected void arrayForEach(int[] array, 673 int from, int to, 674 IntConsumer consumer) { 675 for (int i = from; i < to; i++) 676 consumer.accept(array[i]); 677 } 678 679 @Override 680 public void accept(int i) { 681 preAccept(); 682 curChunk[elementIndex++] = i; 683 } 684 685 public int get(long index) { 686 int ch = chunkFor(index); 687 if (spineIndex == 0 && ch == 0) 688 return curChunk[(int) index]; 689 else 690 return spine[ch][(int) (index-priorElementCount[ch])]; 691 } 692 693 public int[] asIntArray() { 694 return asPrimitiveArray(); 695 } 696 697 @Override 698 public PrimitiveIterator.OfInt iterator() { 699 return Spliterators.iteratorFromSpliterator(spliterator()); 700 } 701 702 public Spliterator.OfInt spliterator() { 703 class Splitr extends BaseSpliterator<Spliterator.OfInt> 704 implements Spliterator.OfInt { 705 706 @Override 707 void arrayForOne(int[] array, int index, IntConsumer consumer) { 708 consumer.accept(array[index]); 709 } 710 711 @Override 712 Spliterator.OfInt arraySpliterator(int[] array, int offset, int len) { 713 return Arrays.spliterator(array, offset, offset+len); 714 } 715 }; 716 return new Splitr(); 717 } 718 719 @Override 720 public String toString() { 721 int[] array = asIntArray(); 722 if (array.length < 200) { 723 return String.format("%s[length=%d, chunks=%d]%s", 724 getClass().getSimpleName(), array.length, 725 spineIndex, Arrays.toString(array)); 726 } 727 else { 728 int[] array2 = Arrays.copyOf(array, 200); 729 return String.format("%s[length=%d, chunks=%d]%s...", 730 getClass().getSimpleName(), array.length, 731 spineIndex, Arrays.toString(array2)); 732 } 733 } 734 } 735 736 /** 737 * An ordered collection of {@code long} values. 738 */ 739 static class OfLong extends SpinedBuffer.OfPrimitive<Long, long[], LongConsumer> 740 implements LongConsumer { 741 OfLong() { } 742 743 OfLong(int initialCapacity) { 744 super(initialCapacity); 745 } 746 747 @Override 748 public void forEach(Consumer<? super Long> consumer) { 749 if (consumer instanceof LongConsumer) { 750 forEach((LongConsumer) consumer); 751 } 752 else { 753 if (Tripwire.ENABLED) 754 Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfLong.forEach(Consumer)"); 755 spliterator().forEachRemaining(consumer); 756 } 757 } 758 759 @Override 760 protected long[][] newArrayArray(int size) { 761 return new long[size][]; 762 } 763 764 @Override 765 protected long[] newArray(int size) { 766 return new long[size]; 767 } 768 769 @Override 770 protected int arrayLength(long[] array) { 771 return array.length; 772 } 773 774 @Override 775 protected void arrayForEach(long[] array, 776 int from, int to, 777 LongConsumer consumer) { 778 for (int i = from; i < to; i++) 779 consumer.accept(array[i]); 780 } 781 782 @Override 783 public void accept(long i) { 784 preAccept(); 785 curChunk[elementIndex++] = i; 786 } 787 788 public long get(long index) { 789 int ch = chunkFor(index); 790 if (spineIndex == 0 && ch == 0) 791 return curChunk[(int) index]; 792 else 793 return spine[ch][(int) (index-priorElementCount[ch])]; 794 } 795 796 public long[] asLongArray() { 797 return asPrimitiveArray(); 798 } 799 800 @Override 801 public PrimitiveIterator.OfLong iterator() { 802 return Spliterators.iteratorFromSpliterator(spliterator()); 803 } 804 805 806 public Spliterator.OfLong spliterator() { 807 class Splitr extends BaseSpliterator<Spliterator.OfLong> 808 implements Spliterator.OfLong { 809 @Override 810 void arrayForOne(long[] array, int index, LongConsumer consumer) { 811 consumer.accept(array[index]); 812 } 813 814 @Override 815 Spliterator.OfLong arraySpliterator(long[] array, int offset, int len) { 816 return Arrays.spliterator(array, offset, offset+len); 817 } 818 }; 819 return new Splitr(); 820 } 821 822 @Override 823 public String toString() { 824 long[] array = asLongArray(); 825 if (array.length < 200) { 826 return String.format("%s[length=%d, chunks=%d]%s", 827 getClass().getSimpleName(), array.length, 828 spineIndex, Arrays.toString(array)); 829 } 830 else { 831 long[] array2 = Arrays.copyOf(array, 200); 832 return String.format("%s[length=%d, chunks=%d]%s...", 833 getClass().getSimpleName(), array.length, 834 spineIndex, Arrays.toString(array2)); 835 } 836 } 837 } 838 839 /** 840 * An ordered collection of {@code double} values. 841 */ 842 static class OfDouble 843 extends SpinedBuffer.OfPrimitive<Double, double[], DoubleConsumer> 844 implements DoubleConsumer { 845 OfDouble() { } 846 847 OfDouble(int initialCapacity) { 848 super(initialCapacity); 849 } 850 851 @Override 852 public void forEach(Consumer<? super Double> consumer) { 853 if (consumer instanceof DoubleConsumer) { 854 forEach((DoubleConsumer) consumer); 855 } 856 else { 857 if (Tripwire.ENABLED) 858 Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfDouble.forEach(Consumer)"); 859 spliterator().forEachRemaining(consumer); 860 } 861 } 862 863 @Override 864 protected double[][] newArrayArray(int size) { 865 return new double[size][]; 866 } 867 868 @Override 869 protected double[] newArray(int size) { 870 return new double[size]; 871 } 872 873 @Override 874 protected int arrayLength(double[] array) { 875 return array.length; 876 } 877 878 @Override 879 protected void arrayForEach(double[] array, 880 int from, int to, 881 DoubleConsumer consumer) { 882 for (int i = from; i < to; i++) 883 consumer.accept(array[i]); 884 } 885 886 @Override 887 public void accept(double i) { 888 preAccept(); 889 curChunk[elementIndex++] = i; 890 } 891 892 public double get(long index) { 893 int ch = chunkFor(index); 894 if (spineIndex == 0 && ch == 0) 895 return curChunk[(int) index]; 896 else 897 return spine[ch][(int) (index-priorElementCount[ch])]; 898 } 899 900 public double[] asDoubleArray() { 901 return asPrimitiveArray(); 902 } 903 904 @Override 905 public PrimitiveIterator.OfDouble iterator() { 906 return Spliterators.iteratorFromSpliterator(spliterator()); 907 } 908 909 public Spliterator.OfDouble spliterator() { 910 class Splitr extends BaseSpliterator<Spliterator.OfDouble> 911 implements Spliterator.OfDouble { 912 @Override 913 void arrayForOne(double[] array, int index, DoubleConsumer consumer) { 914 consumer.accept(array[index]); 915 } 916 917 @Override 918 Spliterator.OfDouble arraySpliterator(double[] array, int offset, int len) { 919 return Arrays.spliterator(array, offset, offset+len); 920 } 921 } 922 return new Splitr(); 923 } 924 925 @Override 926 public String toString() { 927 double[] array = asDoubleArray(); 928 if (array.length < 200) { 929 return String.format("%s[length=%d, chunks=%d]%s", 930 getClass().getSimpleName(), array.length, 931 spineIndex, Arrays.toString(array)); 932 } 933 else { 934 double[] array2 = Arrays.copyOf(array, 200); 935 return String.format("%s[length=%d, chunks=%d]%s...", 936 getClass().getSimpleName(), array.length, 937 spineIndex, Arrays.toString(array2)); 938 } 939 } 940 } 941 } 942