diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2013-11-22 11:18:57 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2013-11-22 11:18:57 -0800 |
| commit | dbccd44a638ae8705a5b14bff8b2dd74abc26045 (patch) | |
| tree | 14bfabaf3f3c7be86dfc064e919e00433a0cf2bb /core/java/android/util/SparseArray.java | |
| parent | ecfae4f899873f224e1aeed076dc8a41f8884487 (diff) | |
| parent | b873a17ce7be0a9771c24999adca6964431728f6 (diff) | |
Merge commit 'b873a17ce7be0a9771c24999adca6964431728f6' into HEAD
Change-Id: I938755073e70602cc8f51ce9bd420fdcf870cecd
Diffstat (limited to 'core/java/android/util/SparseArray.java')
| -rw-r--r-- | core/java/android/util/SparseArray.java | 122 |
1 files changed, 94 insertions, 28 deletions
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 7e8fee56ea95..6e168a8b4ccd 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -20,8 +20,31 @@ import com.android.internal.util.ArrayUtils; /** * SparseArrays map integers to Objects. Unlike a normal array of Objects, - * there can be gaps in the indices. It is intended to be more efficient - * than using a HashMap to map Integers to Objects. + * there can be gaps in the indices. It is intended to be more memory efficient + * than using a HashMap to map Integers to Objects, both because it avoids + * auto-boxing keys and its data structure doesn't rely on an extra entry object + * for each mapping. + * + * <p>Note that this container keeps its mappings in an array data structure, + * using a binary search to find keys. The implementation is not intended to be appropriate for + * data structures + * that may contain large numbers of items. It is generally slower than a traditional + * HashMap, since lookups require a binary search and adds and removes require inserting + * and deleting entries in the array. For containers holding up to hundreds of items, + * the performance difference is not significant, less than 50%.</p> + * + * <p>To help with performance, the container includes an optimization when removing + * keys: instead of compacting its array immediately, it leaves the removed entry marked + * as deleted. The entry can then be re-used for the same key, or compacted later in + * a single garbage collection step of all removed entries. This garbage collection will + * need to be performed at any time the array needs to be grown or the the map size or + * entry values are retrieved.</p> + * + * <p>It is possible to iterate over the items in this container using + * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using + * <code>keyAt(int)</code> with ascending values of the index will return the + * keys in ascending order, or the values corresponding to the keys in ascending + * order in the case of <code>valueAt(int)<code>.</p> */ public class SparseArray<E> implements Cloneable { private static final Object DELETED = new Object(); @@ -41,13 +64,19 @@ public class SparseArray<E> implements Cloneable { /** * Creates a new SparseArray containing no mappings that will not * require any additional memory allocation to store the specified - * number of mappings. + * number of mappings. If you supply an initial capacity of 0, the + * sparse array will be initialized with a light-weight representation + * not requiring any additional array allocations. */ public SparseArray(int initialCapacity) { - initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity); - - mKeys = new int[initialCapacity]; - mValues = new Object[initialCapacity]; + if (initialCapacity == 0) { + mKeys = ContainerHelpers.EMPTY_INTS; + mValues = ContainerHelpers.EMPTY_OBJECTS; + } else { + initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity); + mKeys = new int[initialCapacity]; + mValues = new Object[initialCapacity]; + } mSize = 0; } @@ -79,7 +108,7 @@ public class SparseArray<E> implements Cloneable { */ @SuppressWarnings("unchecked") public E get(int key, E valueIfKeyNotFound) { - int i = binarySearch(mKeys, 0, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i < 0 || mValues[i] == DELETED) { return valueIfKeyNotFound; @@ -92,7 +121,7 @@ public class SparseArray<E> implements Cloneable { * Removes the mapping from the specified key, if there was any. */ public void delete(int key) { - int i = binarySearch(mKeys, 0, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { if (mValues[i] != DELETED) { @@ -119,6 +148,19 @@ public class SparseArray<E> implements Cloneable { } } + /** + * Remove a range of mappings as a batch. + * + * @param index Index to begin at + * @param size Number of mappings to remove + */ + public void removeAtRange(int index, int size) { + final int end = Math.min(mSize, index + size); + for (int i = index; i < end; i++) { + removeAt(i); + } + } + private void gc() { // Log.e("SparseArray", "gc start with " + mSize); @@ -153,7 +195,7 @@ public class SparseArray<E> implements Cloneable { * was one. */ public void put(int key, E value) { - int i = binarySearch(mKeys, 0, mSize, key); + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { mValues[i] = value; @@ -170,7 +212,7 @@ public class SparseArray<E> implements Cloneable { gc(); // Search again because indices may have changed. - i = ~binarySearch(mKeys, 0, mSize, key); + i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); } if (mSize >= mKeys.length) { @@ -215,6 +257,11 @@ public class SparseArray<E> implements Cloneable { * Given an index in the range <code>0...size()-1</code>, returns * the key from the <code>index</code>th key-value mapping that this * SparseArray stores. + * + * <p>The keys corresponding to indices in ascending order are guaranteed to + * be in ascending order, e.g., <code>keyAt(0)</code> will return the + * smallest key and <code>keyAt(size()-1)</code> will return the largest + * key.</p> */ public int keyAt(int index) { if (mGarbage) { @@ -228,6 +275,12 @@ public class SparseArray<E> implements Cloneable { * Given an index in the range <code>0...size()-1</code>, returns * the value from the <code>index</code>th key-value mapping that this * SparseArray stores. + * + * <p>The values corresponding to indices in ascending order are guaranteed + * to be associated with keys in ascending order, e.g., + * <code>valueAt(0)</code> will return the value associated with the + * smallest key and <code>valueAt(size()-1)</code> will return the value + * associated with the largest key.</p> */ @SuppressWarnings("unchecked") public E valueAt(int index) { @@ -261,7 +314,7 @@ public class SparseArray<E> implements Cloneable { gc(); } - return binarySearch(mKeys, 0, mSize, key); + return ContainerHelpers.binarySearch(mKeys, mSize, key); } /** @@ -335,23 +388,36 @@ public class SparseArray<E> implements Cloneable { mSize = pos + 1; } - private static int binarySearch(int[] a, int start, int len, int key) { - int high = start + len, low = start - 1, guess; - - while (high - low > 1) { - guess = (high + low) / 2; - - if (a[guess] < key) - low = guess; - else - high = guess; + /** + * {@inheritDoc} + * + * <p>This implementation composes a string by iterating over its mappings. If + * this map contains itself as a value, the string "(this Map)" + * will appear in its place. + */ + @Override + public String toString() { + if (size() <= 0) { + return "{}"; } - if (high == start + len) - return ~(start + len); - else if (a[high] == key) - return high; - else - return ~high; + StringBuilder buffer = new StringBuilder(mSize * 28); + buffer.append('{'); + for (int i=0; i<mSize; i++) { + if (i > 0) { + buffer.append(", "); + } + int key = keyAt(i); + buffer.append(key); + buffer.append('='); + Object value = valueAt(i); + if (value != this) { + buffer.append(value); + } else { + buffer.append("(this Map)"); + } + } + buffer.append('}'); + return buffer.toString(); } } |
