diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/os/Bundle.java | 30 | ||||
| -rw-r--r-- | core/java/android/os/Parcel.java | 30 | ||||
| -rw-r--r-- | core/java/android/util/ArrayMap.java | 43 |
3 files changed, 84 insertions, 19 deletions
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index b8769b4..2b0ae3a 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -16,15 +16,12 @@ package android.os; +import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import java.io.Serializable; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; import java.util.Set; /** @@ -37,13 +34,13 @@ public final class Bundle implements Parcelable, Cloneable { static { EMPTY = new Bundle(); - EMPTY.mMap = Collections.unmodifiableMap(new HashMap<String, Object>()); + EMPTY.mMap = ArrayMap.EMPTY; } // Invariant - exactly one of mMap / mParcelledData will be null // (except inside a call to unparcel) - /* package */ Map<String, Object> mMap = null; + /* package */ ArrayMap<String, Object> mMap = null; /* * If mParcelledData is non-null, then mMap will be null and the @@ -65,7 +62,7 @@ public final class Bundle implements Parcelable, Cloneable { * Constructs a new, empty Bundle. */ public Bundle() { - mMap = new HashMap<String, Object>(); + mMap = new ArrayMap<String, Object>(); mClassLoader = getClass().getClassLoader(); } @@ -91,7 +88,7 @@ public final class Bundle implements Parcelable, Cloneable { * inside of the Bundle. */ public Bundle(ClassLoader loader) { - mMap = new HashMap<String, Object>(); + mMap = new ArrayMap<String, Object>(); mClassLoader = loader; } @@ -102,7 +99,7 @@ public final class Bundle implements Parcelable, Cloneable { * @param capacity the initial capacity of the Bundle */ public Bundle(int capacity) { - mMap = new HashMap<String, Object>(capacity); + mMap = new ArrayMap<String, Object>(capacity); mClassLoader = getClass().getClassLoader(); } @@ -122,7 +119,7 @@ public final class Bundle implements Parcelable, Cloneable { } if (b.mMap != null) { - mMap = new HashMap<String, Object>(b.mMap); + mMap = new ArrayMap<String, Object>(b.mMap); } else { mMap = null; } @@ -162,7 +159,7 @@ public final class Bundle implements Parcelable, Cloneable { if (size == 0) { return null; } - Object o = mMap.values().iterator().next(); + Object o = mMap.valueAt(0); try { return (String) o; } catch (ClassCastException e) { @@ -218,9 +215,9 @@ public final class Bundle implements Parcelable, Cloneable { return; } if (mMap == null) { - mMap = new HashMap<String, Object>(N); + mMap = new ArrayMap<String, Object>(N); } - mParcelledData.readMapInternal(mMap, N, mClassLoader); + mParcelledData.readArrayMapInternal(mMap, N, mClassLoader); mParcelledData.recycle(); mParcelledData = null; } @@ -331,9 +328,8 @@ public final class Bundle implements Parcelable, Cloneable { } } else { // It's been unparcelled, so we need to walk the map - Iterator<Map.Entry<String, Object>> iter = mMap.entrySet().iterator(); - while (!fdFound && iter.hasNext()) { - Object obj = iter.next().getValue(); + for (int i=mMap.size()-1; i>=0; i--) { + Object obj = mMap.valueAt(i); if (obj instanceof Parcelable) { if ((((Parcelable)obj).describeContents() & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) { @@ -1643,7 +1639,7 @@ public final class Bundle implements Parcelable, Cloneable { parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L' int oldPos = parcel.dataPosition(); - parcel.writeMapInternal(mMap); + parcel.writeArrayMapInternal(mMap); int newPos = parcel.dataPosition(); // Backpatch length diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 0916ea9..12f7915 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -17,6 +17,7 @@ package android.os; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -572,7 +573,7 @@ public final class Parcel { * allows you to avoid mysterious type errors at the point of marshalling. */ public final void writeMap(Map val) { - writeMapInternal((Map<String,Object>) val); + writeMapInternal((Map<String, Object>) val); } /** @@ -593,6 +594,23 @@ public final class Parcel { } /** + * Flatten an ArrayMap into the parcel at the current dataPosition(), + * growing dataCapacity() if needed. The Map keys must be String objects. + */ + /* package */ void writeArrayMapInternal(ArrayMap<String,Object> val) { + if (val == null) { + writeInt(-1); + return; + } + final int N = val.size(); + writeInt(N); + for (int i=0; i<N; i++) { + writeValue(val.keyAt(i)); + writeValue(val.valueAt(i)); + } + } + + /** * Flatten a Bundle into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ @@ -2258,6 +2276,16 @@ public final class Parcel { } } + /* package */ void readArrayMapInternal(ArrayMap outVal, int N, + ClassLoader loader) { + while (N > 0) { + Object key = readValue(loader); + Object value = readValue(loader); + outVal.append(key, value); + N--; + } + } + private void readListInternal(List outVal, int N, ClassLoader loader) { while (N > 0) { diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java index b80a14b..51014c8 100644 --- a/core/java/android/util/ArrayMap.java +++ b/core/java/android/util/ArrayMap.java @@ -61,6 +61,11 @@ public final class ArrayMap<K, V> implements Map<K, V> { private static final int CACHE_SIZE = 10; /** + * @hide Special immutable empty ArrayMap. + */ + public static final ArrayMap EMPTY = new ArrayMap(true); + + /** * Caches of small array objects to avoid spamming garbage. The cache * Object[] variable is a pointer to a linked list of array objects. * The first entry in the array is a pointer to the next array in the @@ -71,6 +76,11 @@ public final class ArrayMap<K, V> implements Map<K, V> { static Object[] mTwiceBaseCache; static int mTwiceBaseCacheSize; + /** + * Special hash array value that indicates the container is immutable. + */ + static final int[] EMPTY_IMMUTABLE_INTS = new int[0]; + int[] mHashes; Object[] mArray; int mSize; @@ -115,6 +125,9 @@ public final class ArrayMap<K, V> implements Map<K, V> { } private void allocArrays(final int size) { + if (mHashes == EMPTY_IMMUTABLE_INTS) { + throw new UnsupportedOperationException("ArrayMap is immutable"); + } if (size == (BASE_SIZE*2)) { synchronized (ArrayMap.class) { if (mTwiceBaseCache != null) { @@ -204,6 +217,12 @@ public final class ArrayMap<K, V> implements Map<K, V> { mSize = 0; } + private ArrayMap(boolean immutable) { + mHashes = EMPTY_IMMUTABLE_INTS; + mArray = ContainerHelpers.EMPTY_OBJECTS; + mSize = 0; + } + /** * Create a new ArrayMap with the mappings from the given ArrayMap. */ @@ -219,7 +238,7 @@ public final class ArrayMap<K, V> implements Map<K, V> { */ @Override public void clear() { - if (mSize != 0) { + if (mSize > 0) { freeArrays(mHashes, mArray, mSize); mHashes = ContainerHelpers.EMPTY_INTS; mArray = ContainerHelpers.EMPTY_OBJECTS; @@ -391,6 +410,28 @@ public final class ArrayMap<K, V> implements Map<K, V> { } /** + * Special fast path for appending items to the end of the array without validation. + * The array must already be large enough to contain the item. + * @hide + */ + public void append(K key, V value) { + int index = mSize; + final int hash = key.hashCode(); + if (index >= mHashes.length) { + throw new IllegalStateException("Array is full"); + } + if (index > 0 && mHashes[index-1] > hash) { + throw new IllegalArgumentException("New hash " + hash + + " is before end of array hash " + mHashes[index-1]); + } + mSize = index+1; + mHashes[index] = hash; + index <<= 1; + mArray[index] = key; + mArray[index+1] = value; + } + + /** * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>array</var> * @param array The array whose contents are to be retrieved. */ |
