1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import static com.google.protobuf.Internal.checkNotNull; 34 35 import com.google.protobuf.Internal.BooleanList; 36 import java.util.Arrays; 37 import java.util.Collection; 38 import java.util.RandomAccess; 39 40 /** 41 * An implementation of {@link BooleanList} on top of a primitive array. 42 * 43 * @author dweis@google.com (Daniel Weis) 44 */ 45 final class BooleanArrayList extends AbstractProtobufList<Boolean> 46 implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection { 47 48 private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(new boolean[0], 0); 49 static { EMPTY_LIST.makeImmutable()50 EMPTY_LIST.makeImmutable(); 51 } 52 emptyList()53 public static BooleanArrayList emptyList() { 54 return EMPTY_LIST; 55 } 56 57 /** The backing store for the list. */ 58 private boolean[] array; 59 60 /** 61 * The size of the list distinct from the length of the array. That is, it is the number of 62 * elements set in the list. 63 */ 64 private int size; 65 66 /** Constructs a new mutable {@code BooleanArrayList} with default capacity. */ BooleanArrayList()67 BooleanArrayList() { 68 this(new boolean[DEFAULT_CAPACITY], 0); 69 } 70 71 /** 72 * Constructs a new mutable {@code BooleanArrayList} containing the same elements as {@code 73 * other}. 74 */ BooleanArrayList(boolean[] other, int size)75 private BooleanArrayList(boolean[] other, int size) { 76 array = other; 77 this.size = size; 78 } 79 80 @Override removeRange(int fromIndex, int toIndex)81 protected void removeRange(int fromIndex, int toIndex) { 82 ensureIsMutable(); 83 if (toIndex < fromIndex) { 84 throw new IndexOutOfBoundsException("toIndex < fromIndex"); 85 } 86 87 System.arraycopy(array, toIndex, array, fromIndex, size - toIndex); 88 size -= (toIndex - fromIndex); 89 modCount++; 90 } 91 92 @Override equals(Object o)93 public boolean equals(Object o) { 94 if (this == o) { 95 return true; 96 } 97 if (!(o instanceof BooleanArrayList)) { 98 return super.equals(o); 99 } 100 BooleanArrayList other = (BooleanArrayList) o; 101 if (size != other.size) { 102 return false; 103 } 104 105 final boolean[] arr = other.array; 106 for (int i = 0; i < size; i++) { 107 if (array[i] != arr[i]) { 108 return false; 109 } 110 } 111 112 return true; 113 } 114 115 @Override hashCode()116 public int hashCode() { 117 int result = 1; 118 for (int i = 0; i < size; i++) { 119 result = (31 * result) + Internal.hashBoolean(array[i]); 120 } 121 return result; 122 } 123 124 @Override mutableCopyWithCapacity(int capacity)125 public BooleanList mutableCopyWithCapacity(int capacity) { 126 if (capacity < size) { 127 throw new IllegalArgumentException(); 128 } 129 return new BooleanArrayList(Arrays.copyOf(array, capacity), size); 130 } 131 132 @Override get(int index)133 public Boolean get(int index) { 134 return getBoolean(index); 135 } 136 137 @Override getBoolean(int index)138 public boolean getBoolean(int index) { 139 ensureIndexInRange(index); 140 return array[index]; 141 } 142 143 @Override indexOf(Object element)144 public int indexOf(Object element) { 145 if (!(element instanceof Boolean)) { 146 return -1; 147 } 148 boolean unboxedElement = (Boolean) element; 149 int numElems = size(); 150 for (int i = 0; i < numElems; i++) { 151 if (array[i] == unboxedElement) { 152 return i; 153 } 154 } 155 return -1; 156 } 157 158 @Override contains(Object element)159 public boolean contains(Object element) { 160 return indexOf(element) != -1; 161 } 162 163 @Override size()164 public int size() { 165 return size; 166 } 167 168 @Override set(int index, Boolean element)169 public Boolean set(int index, Boolean element) { 170 return setBoolean(index, element); 171 } 172 173 @Override setBoolean(int index, boolean element)174 public boolean setBoolean(int index, boolean element) { 175 ensureIsMutable(); 176 ensureIndexInRange(index); 177 boolean previousValue = array[index]; 178 array[index] = element; 179 return previousValue; 180 } 181 182 @Override add(Boolean element)183 public boolean add(Boolean element) { 184 addBoolean(element); 185 return true; 186 } 187 188 @Override add(int index, Boolean element)189 public void add(int index, Boolean element) { 190 addBoolean(index, element); 191 } 192 193 /** Like {@link #add(Boolean)} but more efficient in that it doesn't box the element. */ 194 @Override addBoolean(boolean element)195 public void addBoolean(boolean element) { 196 ensureIsMutable(); 197 if (size == array.length) { 198 // Resize to 1.5x the size 199 int length = ((size * 3) / 2) + 1; 200 boolean[] newArray = new boolean[length]; 201 202 System.arraycopy(array, 0, newArray, 0, size); 203 array = newArray; 204 } 205 206 array[size++] = element; 207 } 208 209 /** Like {@link #add(int, Boolean)} but more efficient in that it doesn't box the element. */ addBoolean(int index, boolean element)210 private void addBoolean(int index, boolean element) { 211 ensureIsMutable(); 212 if (index < 0 || index > size) { 213 throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); 214 } 215 216 if (size < array.length) { 217 // Shift everything over to make room 218 System.arraycopy(array, index, array, index + 1, size - index); 219 } else { 220 // Resize to 1.5x the size 221 int length = ((size * 3) / 2) + 1; 222 boolean[] newArray = new boolean[length]; 223 224 // Copy the first part directly 225 System.arraycopy(array, 0, newArray, 0, index); 226 227 // Copy the rest shifted over by one to make room 228 System.arraycopy(array, index, newArray, index + 1, size - index); 229 array = newArray; 230 } 231 232 array[index] = element; 233 size++; 234 modCount++; 235 } 236 237 @Override addAll(Collection<? extends Boolean> collection)238 public boolean addAll(Collection<? extends Boolean> collection) { 239 ensureIsMutable(); 240 241 checkNotNull(collection); 242 243 // We specialize when adding another BooleanArrayList to avoid boxing elements. 244 if (!(collection instanceof BooleanArrayList)) { 245 return super.addAll(collection); 246 } 247 248 BooleanArrayList list = (BooleanArrayList) collection; 249 if (list.size == 0) { 250 return false; 251 } 252 253 int overflow = Integer.MAX_VALUE - size; 254 if (overflow < list.size) { 255 // We can't actually represent a list this large. 256 throw new OutOfMemoryError(); 257 } 258 259 int newSize = size + list.size; 260 if (newSize > array.length) { 261 array = Arrays.copyOf(array, newSize); 262 } 263 264 System.arraycopy(list.array, 0, array, size, list.size); 265 size = newSize; 266 modCount++; 267 return true; 268 } 269 270 @Override remove(Object o)271 public boolean remove(Object o) { 272 ensureIsMutable(); 273 for (int i = 0; i < size; i++) { 274 if (o.equals(array[i])) { 275 System.arraycopy(array, i + 1, array, i, size - i - 1); 276 size--; 277 modCount++; 278 return true; 279 } 280 } 281 return false; 282 } 283 284 @Override remove(int index)285 public Boolean remove(int index) { 286 ensureIsMutable(); 287 ensureIndexInRange(index); 288 boolean value = array[index]; 289 if (index < size - 1) { 290 System.arraycopy(array, index + 1, array, index, size - index - 1); 291 } 292 size--; 293 modCount++; 294 return value; 295 } 296 297 /** 298 * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an 299 * {@link IndexOutOfBoundsException} if it is not. 300 * 301 * @param index the index to verify is in range 302 */ ensureIndexInRange(int index)303 private void ensureIndexInRange(int index) { 304 if (index < 0 || index >= size) { 305 throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); 306 } 307 } 308 makeOutOfBoundsExceptionMessage(int index)309 private String makeOutOfBoundsExceptionMessage(int index) { 310 return "Index:" + index + ", Size:" + size; 311 } 312 } 313