• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.LongList;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.RandomAccess;
17 
18 /**
19  * An implementation of {@link LongList} on top of a primitive array.
20  *
21  * @author dweis@google.com (Daniel Weis)
22  */
23 final class LongArrayList extends AbstractProtobufList<Long>
24     implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
25 
26   private static final long[] EMPTY_ARRAY = new long[0];
27 
28   private static final LongArrayList EMPTY_LIST = new LongArrayList(EMPTY_ARRAY, 0, false);
29 
emptyList()30   public static LongArrayList emptyList() {
31     return EMPTY_LIST;
32   }
33 
34   /** The backing store for the list. */
35   private long[] 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 LongArrayList} with default capacity. */
LongArrayList()44   LongArrayList() {
45     this(EMPTY_ARRAY, 0, true);
46   }
47 
48   /**
49    * Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
50    */
LongArrayList(long[] other, int size, boolean isMutable)51   private LongArrayList(long[] 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 LongArrayList)) {
75       return super.equals(o);
76     }
77     LongArrayList other = (LongArrayList) o;
78     if (size != other.size) {
79       return false;
80     }
81 
82     final long[] arr = other.array;
83     for (int i = 0; i < size; i++) {
84       if (array[i] != 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) + Internal.hashLong(array[i]);
97     }
98     return result;
99   }
100 
101   @Override
mutableCopyWithCapacity(int capacity)102   public LongList mutableCopyWithCapacity(int capacity) {
103     if (capacity < size) {
104       throw new IllegalArgumentException();
105     }
106     long[] newArray = capacity == 0 ? EMPTY_ARRAY : Arrays.copyOf(array, capacity);
107     return new LongArrayList(newArray, size, true);
108   }
109 
110   @Override
get(int index)111   public Long get(int index) {
112     return getLong(index);
113   }
114 
115   @Override
getLong(int index)116   public long getLong(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 Long)) {
124       return -1;
125     }
126     long unboxedElement = (Long) 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, Long element)147   public Long set(int index, Long element) {
148     return setLong(index, element);
149   }
150 
151   @Override
setLong(int index, long element)152   public long setLong(int index, long element) {
153     ensureIsMutable();
154     ensureIndexInRange(index);
155     long previousValue = array[index];
156     array[index] = element;
157     return previousValue;
158   }
159 
160   @Override
add(Long element)161   public boolean add(Long element) {
162     addLong(element);
163     return true;
164   }
165 
166   @Override
add(int index, Long element)167   public void add(int index, Long element) {
168     addLong(index, element);
169   }
170 
171   /** Like {@link #add(Long)} but more efficient in that it doesn't box the element. */
172   @Override
addLong(long element)173   public void addLong(long element) {
174     ensureIsMutable();
175     if (size == array.length) {
176       int length = growSize(array.length);
177       long[] newArray = new long[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, Long)} but more efficient in that it doesn't box the element. */
addLong(int index, long element)187   private void addLong(int index, long 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       long[] newArray = new long[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 Long> collection)214   public boolean addAll(Collection<? extends Long> collection) {
215     ensureIsMutable();
216 
217     checkNotNull(collection);
218 
219     // We specialize when adding another LongArrayList to avoid boxing elements.
220     if (!(collection instanceof LongArrayList)) {
221       return super.addAll(collection);
222     }
223 
224     LongArrayList list = (LongArrayList) 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 Long remove(int index) {
248     ensureIsMutable();
249     ensureIndexInRange(index);
250     long 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 long[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