1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.util;
18 
19 import android.annotation.Nullable;
20 import android.compat.annotation.UnsupportedAppUsage;
21 
22 import com.android.internal.util.ArrayUtils;
23 import com.android.internal.util.Preconditions;
24 
25 import libcore.util.EmptyArray;
26 
27 import java.util.Arrays;
28 
29 /**
30  * Implements a growing array of long primitives.
31  *
32  * @hide
33  */
34 public class LongArray implements Cloneable {
35     private static final int MIN_CAPACITY_INCREMENT = 12;
36 
37     private long[] mValues;
38     private int mSize;
39 
LongArray(long[] array, int size)40     private  LongArray(long[] array, int size) {
41         mValues = array;
42         mSize = Preconditions.checkArgumentInRange(size, 0, array.length, "size");
43     }
44 
45     /**
46      * Creates an empty LongArray with the default initial capacity.
47      */
48     @UnsupportedAppUsage
LongArray()49     public LongArray() {
50         this(10);
51     }
52 
53     /**
54      * Creates an empty LongArray with the specified initial capacity.
55      */
LongArray(int initialCapacity)56     public LongArray(int initialCapacity) {
57         if (initialCapacity == 0) {
58             mValues = EmptyArray.LONG;
59         } else {
60             mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity);
61         }
62         mSize = 0;
63     }
64 
65     /**
66      * Creates an LongArray wrapping the given primitive long array.
67      */
wrap(long[] array)68     public static LongArray wrap(long[] array) {
69         return new LongArray(array, array.length);
70     }
71 
72     /**
73      * Creates an LongArray from the given primitive long array, copying it.
74      */
fromArray(long[] array, int size)75     public static LongArray fromArray(long[] array, int size) {
76         return wrap(Arrays.copyOf(array, size));
77     }
78 
79     /**
80      * Changes the size of this LongArray. If this LongArray is shrinked, the backing array capacity
81      * is unchanged. If the new size is larger than backing array capacity, a new backing array is
82      * created from the current content of this LongArray padded with 0s.
83      */
resize(int newSize)84     public void resize(int newSize) {
85         Preconditions.checkArgumentNonnegative(newSize);
86         if (newSize <= mValues.length) {
87             Arrays.fill(mValues, newSize, mValues.length, 0);
88         } else {
89             ensureCapacity(newSize - mSize);
90         }
91         mSize = newSize;
92     }
93 
94     /**
95      * Appends the specified value to the end of this array.
96      */
add(long value)97     public void add(long value) {
98         add(mSize, value);
99     }
100 
101     /**
102      * Inserts a value at the specified position in this array. If the specified index is equal to
103      * the length of the array, the value is added at the end.
104      *
105      * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt; size()
106      */
107     @UnsupportedAppUsage
add(int index, long value)108     public void add(int index, long value) {
109         ensureCapacity(1);
110         int rightSegment = mSize - index;
111         mSize++;
112         ArrayUtils.checkBounds(mSize, index);
113 
114         if (rightSegment != 0) {
115             // Move by 1 all values from the right of 'index'
116             System.arraycopy(mValues, index, mValues, index + 1, rightSegment);
117         }
118 
119         mValues[index] = value;
120     }
121 
122     /**
123      * Adds the values in the specified array to this array.
124      */
addAll(LongArray values)125     public void addAll(LongArray values) {
126         final int count = values.mSize;
127         ensureCapacity(count);
128 
129         System.arraycopy(values.mValues, 0, mValues, mSize, count);
130         mSize += count;
131     }
132 
133     /**
134      * Ensures capacity to append at least <code>count</code> values.
135      */
ensureCapacity(int count)136     private void ensureCapacity(int count) {
137         final int currentSize = mSize;
138         final int minCapacity = currentSize + count;
139         if (minCapacity >= mValues.length) {
140             final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ?
141                     MIN_CAPACITY_INCREMENT : currentSize >> 1);
142             final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity;
143             final long[] newValues = ArrayUtils.newUnpaddedLongArray(newCapacity);
144             System.arraycopy(mValues, 0, newValues, 0, currentSize);
145             mValues = newValues;
146         }
147     }
148 
149     /**
150      * Removes all values from this array.
151      */
clear()152     public void clear() {
153         mSize = 0;
154     }
155 
156     @Override
clone()157     public LongArray clone() {
158         LongArray clone = null;
159         try {
160             clone = (LongArray) super.clone();
161             clone.mValues = mValues.clone();
162         } catch (CloneNotSupportedException cnse) {
163             /* ignore */
164         }
165         return clone;
166     }
167 
168     /**
169      * Returns the value at the specified position in this array.
170      */
171     @UnsupportedAppUsage
get(int index)172     public long get(int index) {
173         ArrayUtils.checkBounds(mSize, index);
174         return mValues[index];
175     }
176 
177     /**
178      * Sets the value at the specified position in this array.
179      */
set(int index, long value)180     public void set(int index, long value) {
181         ArrayUtils.checkBounds(mSize, index);
182         mValues[index] = value;
183     }
184 
185     /**
186      * Returns the index of the first occurrence of the specified value in this
187      * array, or -1 if this array does not contain the value.
188      */
indexOf(long value)189     public int indexOf(long value) {
190         final int n = mSize;
191         for (int i = 0; i < n; i++) {
192             if (mValues[i] == value) {
193                 return i;
194             }
195         }
196         return -1;
197     }
198 
199     /**
200      * Removes the value at the specified index from this array.
201      */
remove(int index)202     public void remove(int index) {
203         ArrayUtils.checkBounds(mSize, index);
204         System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1);
205         mSize--;
206     }
207 
208     /**
209      * Returns the number of values in this array.
210      */
211     @UnsupportedAppUsage
size()212     public int size() {
213         return mSize;
214     }
215 
216     /**
217      * Returns a new array with the contents of this LongArray.
218      */
toArray()219     public long[] toArray() {
220         return Arrays.copyOf(mValues, mSize);
221     }
222 
223     /**
224      * Test if each element of {@code a} equals corresponding element from {@code b}
225      */
elementsEqual(@ullable LongArray a, @Nullable LongArray b)226     public static boolean elementsEqual(@Nullable LongArray a, @Nullable LongArray b) {
227         if (a == null || b == null) return a == b;
228         if (a.mSize != b.mSize) return false;
229         for (int i = 0; i < a.mSize; i++) {
230             if (a.get(i) != b.get(i)) {
231                 return false;
232             }
233         }
234         return true;
235     }
236 }
237