Home | History | Annotate | Download | only in protobuf
      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.IntList;
     34 
     35 import java.util.Arrays;
     36 import java.util.Collection;
     37 import java.util.RandomAccess;
     38 
     39 /**
     40  * An implementation of {@link IntList} on top of a primitive array.
     41  *
     42  * @author dweis (at) google.com (Daniel Weis)
     43  */
     44 final class IntArrayList extends AbstractProtobufList<Integer> implements IntList, RandomAccess {
     45 
     46   private static final IntArrayList EMPTY_LIST = new IntArrayList();
     47   static {
     48     EMPTY_LIST.makeImmutable();
     49   }
     50 
     51   public static IntArrayList emptyList() {
     52     return EMPTY_LIST;
     53   }
     54 
     55   /**
     56    * The backing store for the list.
     57    */
     58   private int[] 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 IntArrayList} with default capacity.
     68    */
     69   IntArrayList() {
     70     this(new int[DEFAULT_CAPACITY], 0);
     71   }
     72 
     73   /**
     74    * Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
     75    */
     76   private IntArrayList(int[] array, int size) {
     77     this.array = array;
     78     this.size = size;
     79   }
     80 
     81   @Override
     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     IntArrayList other = (IntArrayList) o;
     90     if (size != other.size) {
     91       return false;
     92     }
     93 
     94     final int[] 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
    105   public int hashCode() {
    106     int result = 1;
    107     for (int i = 0; i < size; i++) {
    108       result = (31 * result) + array[i];
    109     }
    110     return result;
    111   }
    112 
    113   @Override
    114   public IntList mutableCopyWithCapacity(int capacity) {
    115     if (capacity < size) {
    116       throw new IllegalArgumentException();
    117     }
    118     return new IntArrayList(Arrays.copyOf(array, capacity), size);
    119   }
    120 
    121   @Override
    122   public Integer get(int index) {
    123     return getInt(index);
    124   }
    125 
    126   @Override
    127   public int getInt(int index) {
    128     ensureIndexInRange(index);
    129     return array[index];
    130   }
    131 
    132   @Override
    133   public int size() {
    134     return size;
    135   }
    136 
    137   @Override
    138   public Integer set(int index, Integer element) {
    139     return setInt(index, element);
    140   }
    141 
    142   @Override
    143   public int setInt(int index, int element) {
    144     ensureIsMutable();
    145     ensureIndexInRange(index);
    146     int previousValue = array[index];
    147     array[index] = element;
    148     return previousValue;
    149   }
    150 
    151   @Override
    152   public void add(int index, Integer element) {
    153     addInt(index, element);
    154   }
    155 
    156   /**
    157    * Like {@link #add(Integer)} but more efficient in that it doesn't box the element.
    158    */
    159   @Override
    160   public void addInt(int element) {
    161     addInt(size, element);
    162   }
    163 
    164   /**
    165    * Like {@link #add(int, Integer)} but more efficient in that it doesn't box the element.
    166    */
    167   private void addInt(int index, int 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       int[] newArray = new int[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
    195   public boolean addAll(Collection<? extends Integer> collection) {
    196     ensureIsMutable();
    197 
    198     if (collection == null) {
    199       throw new NullPointerException();
    200     }
    201 
    202     // We specialize when adding another IntArrayList to avoid boxing elements.
    203     if (!(collection instanceof IntArrayList)) {
    204       return super.addAll(collection);
    205     }
    206 
    207     IntArrayList list = (IntArrayList) 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
    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
    244   public Integer remove(int index) {
    245     ensureIsMutable();
    246     ensureIndexInRange(index);
    247     int 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    */
    260   private void ensureIndexInRange(int index) {
    261     if (index < 0 || index >= size) {
    262       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
    263     }
    264   }
    265 
    266   private String makeOutOfBoundsExceptionMessage(int index) {
    267     return "Index:" + index + ", Size:" + size;
    268   }
    269 }
    270