1cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn/*
2cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Copyright (C) 2011 The Android Open Source Project
3cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
4cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License");
5cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * you may not use this file except in compliance with the License.
6cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * You may obtain a copy of the License at
7cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
8cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *      http://www.apache.org/licenses/LICENSE-2.0
9cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn *
10cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * Unless required by applicable law or agreed to in writing, software
11cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS,
12cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * See the License for the specific language governing permissions and
14cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn * limitations under the License.
15cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */
16cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
17346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powellpackage android.support.v4.util;
18cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
19cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn/**
200574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov * A copy of Honeycomb's {@link android.util.SparseArray}, that
210574ca37da4619afe4e26753f5a1b4de314b6565Svetoslav Ganov * provides a removeAt() method.
22cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn */
23346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powellpublic class SparseArrayCompat<E> {
24cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    private static final Object DELETED = new Object();
25cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    private boolean mGarbage = false;
26cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
27cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
28cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Creates a new SparseArray containing no mappings.
29cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
30346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell    public SparseArrayCompat() {
31cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        this(10);
32cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
33cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
34cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
35cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Creates a new SparseArray containing no mappings that will not
36cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * require any additional memory allocation to store the specified
37cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * number of mappings.
38cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
39346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell    public SparseArrayCompat(int initialCapacity) {
40cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        initialCapacity = idealIntArraySize(initialCapacity);
41cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
42cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mKeys = new int[initialCapacity];
43cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mValues = new Object[initialCapacity];
44cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mSize = 0;
45cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
46cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
47cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
48cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Gets the Object mapped from the specified key, or <code>null</code>
49cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * if no such mapping has been made.
50cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
51cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public E get(int key) {
52cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return get(key, null);
53cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
54cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
55cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
56cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Gets the Object mapped from the specified key, or the specified Object
57cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * if no such mapping has been made.
58cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
59cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public E get(int key, E valueIfKeyNotFound) {
60cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int i = binarySearch(mKeys, 0, mSize, key);
61cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
62cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (i < 0 || mValues[i] == DELETED) {
63cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return valueIfKeyNotFound;
64cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        } else {
65cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return (E) mValues[i];
66cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
67cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
68cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
69cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
70cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Removes the mapping from the specified key, if there was any.
71cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
72cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void delete(int key) {
73cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int i = binarySearch(mKeys, 0, mSize, key);
74cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
75cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (i >= 0) {
76cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mValues[i] != DELETED) {
77cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mValues[i] = DELETED;
78cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mGarbage = true;
79cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
80cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
81cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
82cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
83cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
84cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Alias for {@link #delete(int)}.
85cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
86cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void remove(int key) {
87cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        delete(key);
88cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
89cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
90cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
91cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Removes the mapping at the specified index.
92cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
93cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void removeAt(int index) {
94cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mValues[index] != DELETED) {
95cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mValues[index] = DELETED;
96cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mGarbage = true;
97cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
98cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
99346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell
100346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell    /**
101346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell     * Remove a range of mappings as a batch.
102346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell     *
103346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell     * @param index Index to begin at
104346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell     * @param size Number of mappings to remove
105346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell     */
106346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell    public void removeAtRange(int index, int size) {
107346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell        final int end = Math.min(mSize, index + size);
108346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell        for (int i = index; i < end; i++) {
109346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell            removeAt(i);
110346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell        }
111346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell    }
112346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell
113cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    private void gc() {
114cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        // Log.e("SparseArray", "gc start with " + mSize);
115cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
116cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int n = mSize;
117cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int o = 0;
118cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int[] keys = mKeys;
119cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        Object[] values = mValues;
120cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
121cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        for (int i = 0; i < n; i++) {
122cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            Object val = values[i];
123cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
124cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (val != DELETED) {
125cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                if (i != o) {
126cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    keys[o] = keys[i];
127cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                    values[o] = val;
128cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                }
129cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
130cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                o++;
131cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
132cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
133cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
134cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mGarbage = false;
135cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mSize = o;
136cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
137cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        // Log.e("SparseArray", "gc end with " + mSize);
138cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
139cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
140cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
141cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Adds a mapping from the specified key to the specified value,
142cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * replacing the previous mapping from the specified key if there
143cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * was one.
144cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
145cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void put(int key, E value) {
146cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int i = binarySearch(mKeys, 0, mSize, key);
147cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
148cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (i >= 0) {
149cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mValues[i] = value;
150cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        } else {
151cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            i = ~i;
152cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
153cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (i < mSize && mValues[i] == DELETED) {
154cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mKeys[i] = key;
155cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mValues[i] = value;
156cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return;
157cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
158cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
159cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mGarbage && mSize >= mKeys.length) {
160cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                gc();
161cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
162cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // Search again because indices may have changed.
163cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                i = ~binarySearch(mKeys, 0, mSize, key);
164cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
165cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
166cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mSize >= mKeys.length) {
167cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                int n = idealIntArraySize(mSize + 1);
168cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
169cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                int[] nkeys = new int[n];
170cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                Object[] nvalues = new Object[n];
171cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
172cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
173cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
174cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
175cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
176cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mKeys = nkeys;
177cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                mValues = nvalues;
178cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
179cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
180cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mSize - i != 0) {
181cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                // Log.e("SparseArray", "move " + (mSize - i));
182cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
183cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
184cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            }
185cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
186cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mKeys[i] = key;
187cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mValues[i] = value;
188cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mSize++;
189cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
190cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
191cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
192cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
193cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Returns the number of key-value mappings that this SparseArray
194cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * currently stores.
195cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
196cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public int size() {
197cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mGarbage) {
198cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            gc();
199cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
200cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
201cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return mSize;
202cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
203cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
204cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
205cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Given an index in the range <code>0...size()-1</code>, returns
206cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * the key from the <code>index</code>th key-value mapping that this
207346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell     * SparseArray stores.
208cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
209cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public int keyAt(int index) {
210cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mGarbage) {
211cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            gc();
212cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
213cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
214cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return mKeys[index];
215cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
216346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell
217cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
218cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Given an index in the range <code>0...size()-1</code>, returns
219cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * the value from the <code>index</code>th key-value mapping that this
220346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell     * SparseArray stores.
221cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
222cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public E valueAt(int index) {
223cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mGarbage) {
224cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            gc();
225cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
226cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
227cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return (E) mValues[index];
228cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
229cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
230cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
231cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Given an index in the range <code>0...size()-1</code>, sets a new
232cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * value for the <code>index</code>th key-value mapping that this
233346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell     * SparseArray stores.
234cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
235cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void setValueAt(int index, E value) {
236cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mGarbage) {
237cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            gc();
238cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
239cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
240cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mValues[index] = value;
241cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
242346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell
243cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
244cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Returns the index for which {@link #keyAt} would return the
245cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * specified key, or a negative number if the specified
246cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * key is not mapped.
247cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
248cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public int indexOfKey(int key) {
249cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mGarbage) {
250cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            gc();
251cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
252cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
253cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return binarySearch(mKeys, 0, mSize, key);
254cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
255cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
256cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
257cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Returns an index for which {@link #valueAt} would return the
258cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * specified key, or a negative number if no keys map to the
259cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * specified value.
260cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Beware that this is a linear search, unlike lookups by key,
261cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * and that multiple keys can map to the same value and this will
262cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * find only one of them.
263cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
264cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public int indexOfValue(E value) {
265cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mGarbage) {
266cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            gc();
267cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
268cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
269cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        for (int i = 0; i < mSize; i++)
270cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (mValues[i] == value)
271cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return i;
272cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
273cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return -1;
274cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
275cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
276cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
277cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Removes all key-value mappings from this SparseArray.
278cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
279cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void clear() {
280cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int n = mSize;
281cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        Object[] values = mValues;
282cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
283cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        for (int i = 0; i < n; i++) {
284cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            values[i] = null;
285cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
286cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
287cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mSize = 0;
288cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mGarbage = false;
289cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
290cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
291cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    /**
292cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * Puts a key/value pair into the array, optimizing for the case where
293cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     * the key is greater than all existing keys in the array.
294cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn     */
295cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    public void append(int key, E value) {
296cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mSize != 0 && key <= mKeys[mSize - 1]) {
297cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            put(key, value);
298cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return;
299cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
300cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
301cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (mGarbage && mSize >= mKeys.length) {
302cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            gc();
303cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
304cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
305cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int pos = mSize;
306cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (pos >= mKeys.length) {
307cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            int n = idealIntArraySize(pos + 1);
308cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
309cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            int[] nkeys = new int[n];
310cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            Object[] nvalues = new Object[n];
311cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
312cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
313cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
314cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
315cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
316cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mKeys = nkeys;
317cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            mValues = nvalues;
318cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
319cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
320cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mKeys[pos] = key;
321cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mValues[pos] = value;
322cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        mSize = pos + 1;
323cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
324346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell
325cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    private static int binarySearch(int[] a, int start, int len, int key) {
326cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        int high = start + len, low = start - 1, guess;
327cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
328cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        while (high - low > 1) {
329cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            guess = (high + low) / 2;
330cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
331cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (a[guess] < key)
332cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                low = guess;
333cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            else
334cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                high = guess;
335cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        }
336cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
337cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        if (high == start + len)
338cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return ~(start + len);
339cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        else if (a[high] == key)
340cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return high;
341cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        else
342cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            return ~high;
343cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
344cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
345cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    static int idealByteArraySize(int need) {
346cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        for (int i = 4; i < 32; i++)
347cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn            if (need <= (1 << i) - 12)
348cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn                return (1 << i) - 12;
349cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn
350cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return need;
351cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
352346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell
353cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    static int idealIntArraySize(int need) {
354cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn        return idealByteArraySize(need * 4) / 4;
355cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    }
356346e2f2390f0d743fd10e7d01a015df6b32292cdAdam Powell
357cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    private int[] mKeys;
358cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    private Object[] mValues;
359cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn    private int mSize;
360cba2e2c881e8e16ea5025b564c94320174d65f01Dianne Hackborn}
361