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 /** 28 * Base class for a data structure for gathering elements into a buffer and then 29 * iterating them. Maintains an array of increasingly sized arrays, so there is 30 * no copying cost associated with growing the data structure. 31 * @since 1.8 32 */ 33 abstract class AbstractSpinedBuffer { 34 /** 35 * Minimum power-of-two for the first chunk. 36 */ 37 public static final int MIN_CHUNK_POWER = 4; 38 39 /** 40 * Minimum size for the first chunk. 41 */ 42 public static final int MIN_CHUNK_SIZE = 1 << MIN_CHUNK_POWER; 43 44 /** 45 * Max power-of-two for chunks. 46 */ 47 public static final int MAX_CHUNK_POWER = 30; 48 49 /** 50 * Minimum array size for array-of-chunks. 51 */ 52 public static final int MIN_SPINE_SIZE = 8; 53 54 55 /** 56 * log2 of the size of the first chunk. 57 */ 58 protected final int initialChunkPower; 59 60 /** 61 * Index of the *next* element to write; may point into, or just outside of, 62 * the current chunk. 63 */ 64 protected int elementIndex; 65 66 /** 67 * Index of the *current* chunk in the spine array, if the spine array is 68 * non-null. 69 */ 70 protected int spineIndex; 71 72 /** 73 * Count of elements in all prior chunks. 74 */ 75 protected long[] priorElementCount; 76 77 /** 78 * Construct with an initial capacity of 16. 79 */ AbstractSpinedBuffer()80 protected AbstractSpinedBuffer() { 81 this.initialChunkPower = MIN_CHUNK_POWER; 82 } 83 84 /** 85 * Construct with a specified initial capacity. 86 * 87 * @param initialCapacity The minimum expected number of elements 88 */ AbstractSpinedBuffer(int initialCapacity)89 protected AbstractSpinedBuffer(int initialCapacity) { 90 if (initialCapacity < 0) 91 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); 92 93 this.initialChunkPower = Math.max(MIN_CHUNK_POWER, 94 Integer.SIZE - Integer.numberOfLeadingZeros(initialCapacity - 1)); 95 } 96 97 /** 98 * Is the buffer currently empty? 99 */ isEmpty()100 public boolean isEmpty() { 101 return (spineIndex == 0) && (elementIndex == 0); 102 } 103 104 /** 105 * How many elements are currently in the buffer? 106 */ count()107 public long count() { 108 return (spineIndex == 0) 109 ? elementIndex 110 : priorElementCount[spineIndex] + elementIndex; 111 } 112 113 /** 114 * How big should the nth chunk be? 115 */ chunkSize(int n)116 protected int chunkSize(int n) { 117 int power = (n == 0 || n == 1) 118 ? initialChunkPower 119 : Math.min(initialChunkPower + n - 1, AbstractSpinedBuffer.MAX_CHUNK_POWER); 120 return 1 << power; 121 } 122 123 /** 124 * Remove all data from the buffer 125 */ clear()126 public abstract void clear(); 127 } 128