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