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