1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 package com.google.protobuf; 9 10 import static com.google.protobuf.Internal.checkNotNull; 11 import static java.lang.Math.max; 12 13 import com.google.protobuf.Internal.FloatList; 14 import java.util.Arrays; 15 import java.util.Collection; 16 import java.util.RandomAccess; 17 18 /** 19 * An implementation of {@link FloatList} on top of a primitive array. 20 * 21 * @author dweis@google.com (Daniel Weis) 22 */ 23 final class FloatArrayList extends AbstractProtobufList<Float> 24 implements FloatList, RandomAccess, PrimitiveNonBoxingCollection { 25 26 private static final float[] EMPTY_ARRAY = new float[0]; 27 28 private static final FloatArrayList EMPTY_LIST = new FloatArrayList(EMPTY_ARRAY, 0, false); 29 emptyList()30 public static FloatArrayList emptyList() { 31 return EMPTY_LIST; 32 } 33 34 /** The backing store for the list. */ 35 private float[] array; 36 37 /** 38 * The size of the list distinct from the length of the array. That is, it is the number of 39 * elements set in the list. 40 */ 41 private int size; 42 43 /** Constructs a new mutable {@code FloatArrayList} with default capacity. */ FloatArrayList()44 FloatArrayList() { 45 this(EMPTY_ARRAY, 0, true); 46 } 47 48 /** 49 * Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}. 50 */ FloatArrayList(float[] other, int size, boolean isMutable)51 private FloatArrayList(float[] other, int size, boolean isMutable) { 52 super(isMutable); 53 this.array = other; 54 this.size = size; 55 } 56 57 @Override removeRange(int fromIndex, int toIndex)58 protected void removeRange(int fromIndex, int toIndex) { 59 ensureIsMutable(); 60 if (toIndex < fromIndex) { 61 throw new IndexOutOfBoundsException("toIndex < fromIndex"); 62 } 63 64 System.arraycopy(array, toIndex, array, fromIndex, size - toIndex); 65 size -= (toIndex - fromIndex); 66 modCount++; 67 } 68 69 @Override equals(Object o)70 public boolean equals(Object o) { 71 if (this == o) { 72 return true; 73 } 74 if (!(o instanceof FloatArrayList)) { 75 return super.equals(o); 76 } 77 FloatArrayList other = (FloatArrayList) o; 78 if (size != other.size) { 79 return false; 80 } 81 82 final float[] arr = other.array; 83 for (int i = 0; i < size; i++) { 84 if (Float.floatToIntBits(array[i]) != Float.floatToIntBits(arr[i])) { 85 return false; 86 } 87 } 88 89 return true; 90 } 91 92 @Override hashCode()93 public int hashCode() { 94 int result = 1; 95 for (int i = 0; i < size; i++) { 96 result = (31 * result) + Float.floatToIntBits(array[i]); 97 } 98 return result; 99 } 100 101 @Override mutableCopyWithCapacity(int capacity)102 public FloatList mutableCopyWithCapacity(int capacity) { 103 if (capacity < size) { 104 throw new IllegalArgumentException(); 105 } 106 float[] newArray = capacity == 0 ? EMPTY_ARRAY : Arrays.copyOf(array, capacity); 107 return new FloatArrayList(newArray, size, true); 108 } 109 110 @Override get(int index)111 public Float get(int index) { 112 return getFloat(index); 113 } 114 115 @Override getFloat(int index)116 public float getFloat(int index) { 117 ensureIndexInRange(index); 118 return array[index]; 119 } 120 121 @Override indexOf(Object element)122 public int indexOf(Object element) { 123 if (!(element instanceof Float)) { 124 return -1; 125 } 126 float unboxedElement = (Float) element; 127 int numElems = size(); 128 for (int i = 0; i < numElems; i++) { 129 if (array[i] == unboxedElement) { 130 return i; 131 } 132 } 133 return -1; 134 } 135 136 @Override contains(Object element)137 public boolean contains(Object element) { 138 return indexOf(element) != -1; 139 } 140 141 @Override size()142 public int size() { 143 return size; 144 } 145 146 @Override set(int index, Float element)147 public Float set(int index, Float element) { 148 return setFloat(index, element); 149 } 150 151 @Override setFloat(int index, float element)152 public float setFloat(int index, float element) { 153 ensureIsMutable(); 154 ensureIndexInRange(index); 155 float previousValue = array[index]; 156 array[index] = element; 157 return previousValue; 158 } 159 160 @Override add(Float element)161 public boolean add(Float element) { 162 addFloat(element); 163 return true; 164 } 165 166 @Override add(int index, Float element)167 public void add(int index, Float element) { 168 addFloat(index, element); 169 } 170 171 /** Like {@link #add(Float)} but more efficient in that it doesn't box the element. */ 172 @Override addFloat(float element)173 public void addFloat(float element) { 174 ensureIsMutable(); 175 if (size == array.length) { 176 int length = growSize(array.length); 177 float[] newArray = new float[length]; 178 179 System.arraycopy(array, 0, newArray, 0, size); 180 array = newArray; 181 } 182 183 array[size++] = element; 184 } 185 186 /** Like {@link #add(int, Float)} but more efficient in that it doesn't box the element. */ addFloat(int index, float element)187 private void addFloat(int index, float element) { 188 ensureIsMutable(); 189 if (index < 0 || index > size) { 190 throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); 191 } 192 193 if (size < array.length) { 194 // Shift everything over to make room 195 System.arraycopy(array, index, array, index + 1, size - index); 196 } else { 197 int length = growSize(array.length); 198 float[] newArray = new float[length]; 199 200 // Copy the first part directly 201 System.arraycopy(array, 0, newArray, 0, index); 202 203 // Copy the rest shifted over by one to make room 204 System.arraycopy(array, index, newArray, index + 1, size - index); 205 array = newArray; 206 } 207 208 array[index] = element; 209 size++; 210 modCount++; 211 } 212 213 @Override addAll(Collection<? extends Float> collection)214 public boolean addAll(Collection<? extends Float> collection) { 215 ensureIsMutable(); 216 217 checkNotNull(collection); 218 219 // We specialize when adding another FloatArrayList to avoid boxing elements. 220 if (!(collection instanceof FloatArrayList)) { 221 return super.addAll(collection); 222 } 223 224 FloatArrayList list = (FloatArrayList) collection; 225 if (list.size == 0) { 226 return false; 227 } 228 229 int overflow = Integer.MAX_VALUE - size; 230 if (overflow < list.size) { 231 // We can't actually represent a list this large. 232 throw new OutOfMemoryError(); 233 } 234 235 int newSize = size + list.size; 236 if (newSize > array.length) { 237 array = Arrays.copyOf(array, newSize); 238 } 239 240 System.arraycopy(list.array, 0, array, size, list.size); 241 size = newSize; 242 modCount++; 243 return true; 244 } 245 246 @Override remove(int index)247 public Float remove(int index) { 248 ensureIsMutable(); 249 ensureIndexInRange(index); 250 float value = array[index]; 251 if (index < size - 1) { 252 System.arraycopy(array, index + 1, array, index, size - index - 1); 253 } 254 size--; 255 modCount++; 256 return value; 257 } 258 259 /** Ensures the backing array can fit at least minCapacity elements. */ ensureCapacity(int minCapacity)260 void ensureCapacity(int minCapacity) { 261 if (minCapacity <= array.length) { 262 return; 263 } 264 if (array.length == 0) { 265 array = new float[max(minCapacity, DEFAULT_CAPACITY)]; 266 return; 267 } 268 // To avoid quadratic copying when calling .addAllFoo(List) in a loop, we must not size to 269 // exactly the requested capacity, but must exponentially grow instead. This is similar 270 // behaviour to ArrayList. 271 int n = array.length; 272 while (n < minCapacity) { 273 n = growSize(n); 274 } 275 array = Arrays.copyOf(array, n); 276 } 277 growSize(int previousSize)278 private static int growSize(int previousSize) { 279 // Resize to 1.5x the size, rounding up to DEFAULT_CAPACITY. 280 return max(((previousSize * 3) / 2) + 1, DEFAULT_CAPACITY); 281 } 282 283 /** 284 * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an 285 * {@link IndexOutOfBoundsException} if it is not. 286 * 287 * @param index the index to verify is in range 288 */ ensureIndexInRange(int index)289 private void ensureIndexInRange(int index) { 290 if (index < 0 || index >= size) { 291 throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); 292 } 293 } 294 makeOutOfBoundsExceptionMessage(int index)295 private String makeOutOfBoundsExceptionMessage(int index) { 296 return "Index:" + index + ", Size:" + size; 297 } 298 } 299