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