Home | History | Annotate | Download | only in stream
      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.Objects;
     32 import java.util.PrimitiveIterator;
     33 import java.util.Spliterator;
     34 import java.util.Spliterators;
     35 import java.util.function.Consumer;
     36 import java.util.function.DoubleConsumer;
     37 import java.util.function.IntConsumer;
     38 import java.util.function.IntFunction;
     39 import 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  */
     57 public 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      * @param  the 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