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 50 static { EMPTY_LIST.makeImmutable()51 EMPTY_LIST.makeImmutable(); 52 } 53 emptyList()54 public static BooleanArrayList emptyList() { 55 return EMPTY_LIST; 56 } 57 58 /** The backing store for the list. */ 59 private boolean[] array; 60 61 /** 62 * The size of the list distinct from the length of the array. That is, it is the number of 63 * elements set in the list. 64 */ 65 private int size; 66 67 /** Constructs a new mutable {@code BooleanArrayList} with default capacity. */ BooleanArrayList()68 BooleanArrayList() { 69 this(new boolean[DEFAULT_CAPACITY], 0); 70 } 71 72 /** 73 * Constructs a new mutable {@code BooleanArrayList} containing the same elements as {@code 74 * other}. 75 */ BooleanArrayList(boolean[] other, int size)76 private BooleanArrayList(boolean[] other, int size) { 77 array = other; 78 this.size = size; 79 } 80 81 @Override removeRange(int fromIndex, int toIndex)82 protected void removeRange(int fromIndex, int toIndex) { 83 ensureIsMutable(); 84 if (toIndex < fromIndex) { 85 throw new IndexOutOfBoundsException("toIndex < fromIndex"); 86 } 87 88 System.arraycopy(array, toIndex, array, fromIndex, size - toIndex); 89 size -= (toIndex - fromIndex); 90 modCount++; 91 } 92 93 @Override equals(Object o)94 public boolean equals(Object o) { 95 if (this == o) { 96 return true; 97 } 98 if (!(o instanceof BooleanArrayList)) { 99 return super.equals(o); 100 } 101 BooleanArrayList other = (BooleanArrayList) o; 102 if (size != other.size) { 103 return false; 104 } 105 106 final boolean[] arr = other.array; 107 for (int i = 0; i < size; i++) { 108 if (array[i] != arr[i]) { 109 return false; 110 } 111 } 112 113 return true; 114 } 115 116 @Override hashCode()117 public int hashCode() { 118 int result = 1; 119 for (int i = 0; i < size; i++) { 120 result = (31 * result) + Internal.hashBoolean(array[i]); 121 } 122 return result; 123 } 124 125 @Override mutableCopyWithCapacity(int capacity)126 public BooleanList mutableCopyWithCapacity(int capacity) { 127 if (capacity < size) { 128 throw new IllegalArgumentException(); 129 } 130 return new BooleanArrayList(Arrays.copyOf(array, capacity), size); 131 } 132 133 @Override get(int index)134 public Boolean get(int index) { 135 return getBoolean(index); 136 } 137 138 @Override getBoolean(int index)139 public boolean getBoolean(int index) { 140 ensureIndexInRange(index); 141 return array[index]; 142 } 143 144 @Override size()145 public int size() { 146 return size; 147 } 148 149 @Override set(int index, Boolean element)150 public Boolean set(int index, Boolean element) { 151 return setBoolean(index, element); 152 } 153 154 @Override setBoolean(int index, boolean element)155 public boolean setBoolean(int index, boolean element) { 156 ensureIsMutable(); 157 ensureIndexInRange(index); 158 boolean previousValue = array[index]; 159 array[index] = element; 160 return previousValue; 161 } 162 163 @Override add(int index, Boolean element)164 public void add(int index, Boolean element) { 165 addBoolean(index, element); 166 } 167 168 /** Like {@link #add(Boolean)} but more efficient in that it doesn't box the element. */ 169 @Override addBoolean(boolean element)170 public void addBoolean(boolean element) { 171 addBoolean(size, element); 172 } 173 174 /** Like {@link #add(int, Boolean)} but more efficient in that it doesn't box the element. */ addBoolean(int index, boolean element)175 private void addBoolean(int index, boolean element) { 176 ensureIsMutable(); 177 if (index < 0 || index > size) { 178 throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); 179 } 180 181 if (size < array.length) { 182 // Shift everything over to make room 183 System.arraycopy(array, index, array, index + 1, size - index); 184 } else { 185 // Resize to 1.5x the size 186 int length = ((size * 3) / 2) + 1; 187 boolean[] newArray = new boolean[length]; 188 189 // Copy the first part directly 190 System.arraycopy(array, 0, newArray, 0, index); 191 192 // Copy the rest shifted over by one to make room 193 System.arraycopy(array, index, newArray, index + 1, size - index); 194 array = newArray; 195 } 196 197 array[index] = element; 198 size++; 199 modCount++; 200 } 201 202 @Override addAll(Collection<? extends Boolean> collection)203 public boolean addAll(Collection<? extends Boolean> collection) { 204 ensureIsMutable(); 205 206 checkNotNull(collection); 207 208 // We specialize when adding another BooleanArrayList to avoid boxing elements. 209 if (!(collection instanceof BooleanArrayList)) { 210 return super.addAll(collection); 211 } 212 213 BooleanArrayList list = (BooleanArrayList) collection; 214 if (list.size == 0) { 215 return false; 216 } 217 218 int overflow = Integer.MAX_VALUE - size; 219 if (overflow < list.size) { 220 // We can't actually represent a list this large. 221 throw new OutOfMemoryError(); 222 } 223 224 int newSize = size + list.size; 225 if (newSize > array.length) { 226 array = Arrays.copyOf(array, newSize); 227 } 228 229 System.arraycopy(list.array, 0, array, size, list.size); 230 size = newSize; 231 modCount++; 232 return true; 233 } 234 235 @Override remove(Object o)236 public boolean remove(Object o) { 237 ensureIsMutable(); 238 for (int i = 0; i < size; i++) { 239 if (o.equals(array[i])) { 240 System.arraycopy(array, i + 1, array, i, size - i - 1); 241 size--; 242 modCount++; 243 return true; 244 } 245 } 246 return false; 247 } 248 249 @Override remove(int index)250 public Boolean remove(int index) { 251 ensureIsMutable(); 252 ensureIndexInRange(index); 253 boolean value = array[index]; 254 if (index < size - 1) { 255 System.arraycopy(array, index + 1, array, index, size - index - 1); 256 } 257 size--; 258 modCount++; 259 return value; 260 } 261 262 /** 263 * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an 264 * {@link IndexOutOfBoundsException} if it is not. 265 * 266 * @param index the index to verify is in range 267 */ ensureIndexInRange(int index)268 private void ensureIndexInRange(int index) { 269 if (index < 0 || index >= size) { 270 throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); 271 } 272 } 273 makeOutOfBoundsExceptionMessage(int index)274 private String makeOutOfBoundsExceptionMessage(int index) { 275 return "Index:" + index + ", Size:" + size; 276 } 277 } 278