1 /* 2 * Copyright (C) 2010 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.replica.replicaisland; 18 19 import java.util.Arrays; 20 import java.util.Comparator; 21 22 /** 23 * FixedSizeArray is an alternative to a standard Java collection like ArrayList. It is designed 24 * to provide a contiguous array of fixed length which can be accessed, sorted, and searched without 25 * requiring any runtime allocation. This implementation makes a distinction between the "capacity" 26 * of an array (the maximum number of objects it can contain) and the "count" of an array 27 * (the current number of objects inserted into the array). Operations such as set() and remove() 28 * can only operate on objects that have been explicitly add()-ed to the array; that is, indexes 29 * larger than getCount() but smaller than getCapacity() can't be used on their own. 30 * @param <T> The type of object that this array contains. 31 */ 32 public class FixedSizeArray<T> extends AllocationGuard { 33 private final static int LINEAR_SEARCH_CUTOFF = 16; 34 private final T[] mContents; 35 private int mCount; 36 private Comparator<T> mComparator; 37 private boolean mSorted; 38 private Sorter<T> mSorter; 39 40 public FixedSizeArray(int size) { 41 super(); 42 assert size > 0; 43 // Ugh! No generic array construction in Java. 44 mContents = (T[])new Object[size]; 45 mCount = 0; 46 mSorted = false; 47 48 mSorter = new StandardSorter<T>(); 49 } 50 51 public FixedSizeArray(int size, Comparator<T> comparator) { 52 super(); 53 assert size > 0; 54 mContents = (T[])new Object[size]; 55 mCount = 0; 56 mComparator = comparator; 57 mSorted = false; 58 59 mSorter = new StandardSorter<T>(); 60 } 61 62 /** 63 * Inserts a new object into the array. If the array is full, an assert is thrown and the 64 * object is ignored. 65 */ 66 public final void add(T object) { 67 assert mCount < mContents.length : "Array exhausted!"; 68 if (mCount < mContents.length) { 69 mContents[mCount] = object; 70 mSorted = false; 71 mCount++; 72 } 73 } 74 75 /** 76 * Searches for an object and removes it from the array if it is found. Other indexes in the 77 * array are shifted up to fill the space left by the removed object. Note that if 78 * ignoreComparator is set to true, a linear search of object references will be performed. 79 * Otherwise, the comparator set on this array (if any) will be used to find the object. 80 */ 81 public void remove(T object, boolean ignoreComparator) { 82 final int index = find(object, ignoreComparator); 83 if (index != -1) { 84 remove(index); 85 } 86 } 87 88 /** 89 * Removes the specified index from the array. Subsequent entries in the array are shifted up 90 * to fill the space. 91 */ 92 public void remove(int index) { 93 assert index < mCount; 94 // ugh 95 if (index < mCount) { 96 for (int x = index; x < mCount; x++) { 97 if (x + 1 < mContents.length && x + 1 < mCount) { 98 mContents[x] = mContents[x + 1]; 99 } else { 100 mContents[x] = null; 101 } 102 } 103 mCount--; 104 } 105 } 106 107 /** 108 * Removes the last element in the array and returns it. This method is faster than calling 109 * remove(count -1); 110 * @return The contents of the last element in the array. 111 */ 112 public T removeLast() { 113 T object = null; 114 if (mCount > 0) { 115 object = mContents[mCount - 1]; 116 mContents[mCount - 1] = null; 117 mCount--; 118 } 119 return object; 120 } 121 122 /** 123 * Swaps the element at the passed index with the element at the end of the array. When 124 * followed by removeLast(), this is useful for quickly removing array elements. 125 */ 126 public void swapWithLast(int index) { 127 if (mCount > 0 && index < mCount - 1) { 128 T object = mContents[mCount - 1]; 129 mContents[mCount - 1] = mContents[index]; 130 mContents[index] = object; 131 mSorted = false; 132 } 133 } 134 135 /** 136 * Sets the value of a specific index in the array. An object must have already been added to 137 * the array at that index for this command to complete. 138 */ 139 public void set(int index, T object) { 140 assert index < mCount; 141 if (index < mCount) { 142 mContents[index] = object; 143 } 144 } 145 146 /** 147 * Clears the contents of the array, releasing all references to objects it contains and 148 * setting its count to zero. 149 */ 150 public void clear() { 151 for (int x = 0; x < mCount; x++) { 152 mContents[x] = null; 153 } 154 mCount = 0; 155 mSorted = false; 156 } 157 158 /** 159 * Returns an entry from the array at the specified index. 160 */ 161 public T get(int index) { 162 assert index < mCount; 163 T result = null; 164 if (index < mCount && index >= 0) { 165 result = mContents[index]; 166 } 167 return result; 168 } 169 170 /** 171 * Returns the raw internal array. Exposed here so that tight loops can cache this array 172 * and walk it without the overhead of repeated function calls. Beware that changing this array 173 * can leave FixedSizeArray in an undefined state, so this function is potentially dangerous 174 * and should be used in read-only cases. 175 * @return The internal storage array. 176 */ 177 public final Object[] getArray() { 178 return mContents; 179 } 180 181 182 /** 183 * Searches the array for the specified object. If the array has been sorted with sort(), 184 * and if no other order-changing events have occurred since the sort (e.g. add()), a 185 * binary search will be performed. If a comparator has been specified with setComparator(), 186 * it will be used to perform the search. If not, the default comparator for the object type 187 * will be used. If the array is unsorted, a linear search is performed. 188 * Note that if ignoreComparator is set to true, a linear search of object references will be 189 * performed. Otherwise, the comparator set on this array (if any) will be used to find the 190 * object. 191 * @param object The object to search for. 192 * @return The index of the object in the array, or -1 if the object is not found. 193 */ 194 public int find(T object, boolean ignoreComparator) { 195 int index = -1; 196 final int count = mCount; 197 final boolean sorted = mSorted; 198 final Comparator comparator = mComparator; 199 final T[] contents = mContents; 200 if (sorted && !ignoreComparator && count > LINEAR_SEARCH_CUTOFF) { 201 if (comparator != null) { 202 index = Arrays.binarySearch(contents, object, comparator); 203 } else { 204 index = Arrays.binarySearch(contents, object); 205 } 206 // Arrays.binarySearch() returns a negative insertion index if the object isn't found, 207 // but we just want a boolean. 208 if (index < 0) { 209 index = -1; 210 } 211 } else { 212 // unsorted, linear search 213 214 if (comparator != null && !ignoreComparator) { 215 for (int x = 0; x < count; x++) { 216 final int result = comparator.compare(contents[x], object); 217 if (result == 0) { 218 index = x; 219 break; 220 } else if (result > 0 && sorted) { 221 // we've passed the object, early out 222 break; 223 } 224 } 225 } else { 226 for (int x = 0; x < count; x++) { 227 if (contents[x] == object) { 228 index = x; 229 break; 230 } 231 } 232 } 233 } 234 return index; 235 } 236 237 /** 238 * Sorts the array. If the array is already sorted, no work will be performed unless 239 * the forceResort parameter is set to true. If a comparator has been specified with 240 * setComparator(), it will be used for the sort; otherwise the object's natural ordering will 241 * be used. 242 * @param forceResort If set to true, the array will be resorted even if the order of the 243 * objects in the array has not changed since the last sort. 244 */ 245 public void sort(boolean forceResort) { 246 if (!mSorted || forceResort) { 247 if (mComparator != null) { 248 mSorter.sort(mContents, mCount, mComparator); 249 } else { 250 DebugLog.d("FixedSizeArray", "No comparator specified for this type, using Arrays.sort()."); 251 252 Arrays.sort(mContents, 0, mCount); 253 } 254 mSorted = true; 255 } 256 } 257 258 /** Returns the number of objects in the array. */ 259 public int getCount() { 260 return mCount; 261 } 262 263 /** Returns the maximum number of objects that can be inserted inot this array. */ 264 public int getCapacity() { 265 return mContents.length; 266 } 267 268 /** Sets a comparator to use for sorting and searching. */ 269 public void setComparator(Comparator<T> comparator) { 270 mComparator = comparator; 271 mSorted = false; 272 } 273 274 public void setSorter(Sorter<T> sorter) { 275 mSorter = sorter; 276 } 277 } 278