1 /* 2 * Copyright (C) 2019 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 com.android.providers.media.util; 18 19 import java.util.Arrays; 20 21 /** 22 * Implements a growing array of long primitives. 23 * 24 * @hide 25 */ 26 public class LongArray implements Cloneable { 27 private static final int MIN_CAPACITY_INCREMENT = 12; 28 29 private long[] mValues; 30 private int mSize; 31 LongArray(long[] array, int size)32 private LongArray(long[] array, int size) { 33 mValues = array; 34 mSize = checkArgumentInRange(size, 0, array.length, "size"); 35 } 36 37 /** 38 * Creates an empty LongArray with the default initial capacity. 39 */ LongArray()40 public LongArray() { 41 this(10); 42 } 43 44 /** 45 * Creates an empty LongArray with the specified initial capacity. 46 */ LongArray(int initialCapacity)47 public LongArray(int initialCapacity) { 48 if (initialCapacity == 0) { 49 mValues = new long[0]; 50 } else { 51 mValues = new long[initialCapacity]; 52 } 53 mSize = 0; 54 } 55 56 /** 57 * Creates an LongArray wrapping the given primitive long array. 58 */ wrap(long[] array)59 public static LongArray wrap(long[] array) { 60 return new LongArray(array, array.length); 61 } 62 63 /** 64 * Creates an LongArray from the given primitive long array, copying it. 65 */ fromArray(long[] array, int size)66 public static LongArray fromArray(long[] array, int size) { 67 return wrap(Arrays.copyOf(array, size)); 68 } 69 70 /** 71 * Changes the size of this LongArray. If this LongArray is shrinked, the backing array capacity 72 * is unchanged. If the new size is larger than backing array capacity, a new backing array is 73 * created from the current content of this LongArray padded with 0s. 74 */ resize(int newSize)75 public void resize(int newSize) { 76 checkArgumentNonnegative(newSize); 77 if (newSize <= mValues.length) { 78 Arrays.fill(mValues, newSize, mValues.length, 0); 79 } else { 80 ensureCapacity(newSize - mSize); 81 } 82 mSize = newSize; 83 } 84 85 /** 86 * Appends the specified value to the end of this array. 87 */ add(long value)88 public void add(long value) { 89 add(mSize, value); 90 } 91 92 /** 93 * Inserts a value at the specified position in this array. If the specified index is equal to 94 * the length of the array, the value is added at the end. 95 * 96 * @throws IndexOutOfBoundsException when index < 0 || index > size() 97 */ add(int index, long value)98 public void add(int index, long value) { 99 ensureCapacity(1); 100 int rightSegment = mSize - index; 101 mSize++; 102 checkBounds(mSize, index); 103 104 if (rightSegment != 0) { 105 // Move by 1 all values from the right of 'index' 106 System.arraycopy(mValues, index, mValues, index + 1, rightSegment); 107 } 108 109 mValues[index] = value; 110 } 111 112 /** 113 * Adds the values in the specified array to this array. 114 */ addAll(LongArray values)115 public void addAll(LongArray values) { 116 final int count = values.mSize; 117 ensureCapacity(count); 118 119 System.arraycopy(values.mValues, 0, mValues, mSize, count); 120 mSize += count; 121 } 122 123 /** 124 * Ensures capacity to append at least <code>count</code> values. 125 */ ensureCapacity(int count)126 private void ensureCapacity(int count) { 127 final int currentSize = mSize; 128 final int minCapacity = currentSize + count; 129 if (minCapacity >= mValues.length) { 130 final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ? 131 MIN_CAPACITY_INCREMENT : currentSize >> 1); 132 final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity; 133 final long[] newValues = new long[newCapacity]; 134 System.arraycopy(mValues, 0, newValues, 0, currentSize); 135 mValues = newValues; 136 } 137 } 138 139 /** 140 * Removes all values from this array. 141 */ clear()142 public void clear() { 143 mSize = 0; 144 } 145 146 @Override clone()147 public LongArray clone() { 148 LongArray clone = null; 149 try { 150 clone = (LongArray) super.clone(); 151 clone.mValues = mValues.clone(); 152 } catch (CloneNotSupportedException cnse) { 153 /* ignore */ 154 } 155 return clone; 156 } 157 158 /** 159 * Returns the value at the specified position in this array. 160 */ get(int index)161 public long get(int index) { 162 checkBounds(mSize, index); 163 return mValues[index]; 164 } 165 166 /** 167 * Sets the value at the specified position in this array. 168 */ set(int index, long value)169 public void set(int index, long value) { 170 checkBounds(mSize, index); 171 mValues[index] = value; 172 } 173 174 /** 175 * Returns the index of the first occurrence of the specified value in this 176 * array, or -1 if this array does not contain the value. 177 */ indexOf(long value)178 public int indexOf(long value) { 179 final int n = mSize; 180 for (int i = 0; i < n; i++) { 181 if (mValues[i] == value) { 182 return i; 183 } 184 } 185 return -1; 186 } 187 188 /** 189 * Removes the value at the specified index from this array. 190 */ remove(int index)191 public void remove(int index) { 192 checkBounds(mSize, index); 193 System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1); 194 mSize--; 195 } 196 197 /** 198 * Returns the number of values in this array. 199 */ size()200 public int size() { 201 return mSize; 202 } 203 204 /** 205 * Returns a new array with the contents of this LongArray. 206 */ toArray()207 public long[] toArray() { 208 return Arrays.copyOf(mValues, mSize); 209 } 210 211 /** 212 * Test if each element of {@code a} equals corresponding element from {@code b} 213 */ elementsEqual(LongArray a, LongArray b)214 public static boolean elementsEqual(LongArray a, LongArray b) { 215 if (a == null || b == null) return a == b; 216 if (a.mSize != b.mSize) return false; 217 for (int i = 0; i < a.mSize; i++) { 218 if (a.get(i) != b.get(i)) { 219 return false; 220 } 221 } 222 return true; 223 } 224 checkArgumentNonnegative(final int value)225 public static int checkArgumentNonnegative(final int value) { 226 if (value < 0) { 227 throw new IllegalArgumentException(); 228 } 229 230 return value; 231 } 232 checkArgumentInRange(int value, int lower, int upper, String valueName)233 public static int checkArgumentInRange(int value, int lower, int upper, 234 String valueName) { 235 if (value < lower) { 236 throw new IllegalArgumentException( 237 String.format( 238 "%s is out of range of [%d, %d] (too low)", valueName, lower, upper)); 239 } else if (value > upper) { 240 throw new IllegalArgumentException( 241 String.format( 242 "%s is out of range of [%d, %d] (too high)", valueName, lower, upper)); 243 } 244 245 return value; 246 } 247 checkBounds(int len, int index)248 public static void checkBounds(int len, int index) { 249 if (index < 0 || len <= index) { 250 throw new ArrayIndexOutOfBoundsException("length=" + len + "; index=" + index); 251 } 252 } 253 } 254