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