• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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 android.util;
18 
19 import com.android.internal.util.ArrayUtils;
20 
21 /**
22  * SparseIntArrays map integers to integers.  Unlike a normal array of integers,
23  * there can be gaps in the indices.  It is intended to be more efficient
24  * than using a HashMap to map Integers to Integers.
25  */
26 public class SparseIntArray {
27     /**
28      * Creates a new SparseIntArray containing no mappings.
29      */
SparseIntArray()30     public SparseIntArray() {
31         this(10);
32     }
33 
34     /**
35      * Creates a new SparseIntArray containing no mappings that will not
36      * require any additional memory allocation to store the specified
37      * number of mappings.
38      */
SparseIntArray(int initialCapacity)39     public SparseIntArray(int initialCapacity) {
40         initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
41 
42         mKeys = new int[initialCapacity];
43         mValues = new int[initialCapacity];
44         mSize = 0;
45     }
46 
47     /**
48      * Gets the int mapped from the specified key, or <code>0</code>
49      * if no such mapping has been made.
50      */
get(int key)51     public int get(int key) {
52         return get(key, 0);
53     }
54 
55     /**
56      * Gets the int mapped from the specified key, or the specified value
57      * if no such mapping has been made.
58      */
get(int key, int valueIfKeyNotFound)59     public int get(int key, int valueIfKeyNotFound) {
60         int i = binarySearch(mKeys, 0, mSize, key);
61 
62         if (i < 0) {
63             return valueIfKeyNotFound;
64         } else {
65             return mValues[i];
66         }
67     }
68 
69     /**
70      * Removes the mapping from the specified key, if there was any.
71      */
delete(int key)72     public void delete(int key) {
73         int i = binarySearch(mKeys, 0, mSize, key);
74 
75         if (i >= 0) {
76             removeAt(i);
77         }
78     }
79 
80     /**
81      * Removes the mapping at the given index.
82      */
removeAt(int index)83     public void removeAt(int index) {
84         System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
85         System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1));
86         mSize--;
87     }
88 
89     /**
90      * Adds a mapping from the specified key to the specified value,
91      * replacing the previous mapping from the specified key if there
92      * was one.
93      */
put(int key, int value)94     public void put(int key, int value) {
95         int i = binarySearch(mKeys, 0, mSize, key);
96 
97         if (i >= 0) {
98             mValues[i] = value;
99         } else {
100             i = ~i;
101 
102             if (mSize >= mKeys.length) {
103                 int n = ArrayUtils.idealIntArraySize(mSize + 1);
104 
105                 int[] nkeys = new int[n];
106                 int[] nvalues = new int[n];
107 
108                 // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
109                 System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
110                 System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
111 
112                 mKeys = nkeys;
113                 mValues = nvalues;
114             }
115 
116             if (mSize - i != 0) {
117                 // Log.e("SparseIntArray", "move " + (mSize - i));
118                 System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
119                 System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
120             }
121 
122             mKeys[i] = key;
123             mValues[i] = value;
124             mSize++;
125         }
126     }
127 
128     /**
129      * Returns the number of key-value mappings that this SparseIntArray
130      * currently stores.
131      */
size()132     public int size() {
133         return mSize;
134     }
135 
136     /**
137      * Given an index in the range <code>0...size()-1</code>, returns
138      * the key from the <code>index</code>th key-value mapping that this
139      * SparseIntArray stores.
140      */
keyAt(int index)141     public int keyAt(int index) {
142         return mKeys[index];
143     }
144 
145     /**
146      * Given an index in the range <code>0...size()-1</code>, returns
147      * the value from the <code>index</code>th key-value mapping that this
148      * SparseIntArray stores.
149      */
valueAt(int index)150     public int valueAt(int index) {
151         return mValues[index];
152     }
153 
154     /**
155      * Returns the index for which {@link #keyAt} would return the
156      * specified key, or a negative number if the specified
157      * key is not mapped.
158      */
indexOfKey(int key)159     public int indexOfKey(int key) {
160         return binarySearch(mKeys, 0, mSize, key);
161     }
162 
163     /**
164      * Returns an index for which {@link #valueAt} would return the
165      * specified key, or a negative number if no keys map to the
166      * specified value.
167      * Beware that this is a linear search, unlike lookups by key,
168      * and that multiple keys can map to the same value and this will
169      * find only one of them.
170      */
indexOfValue(int value)171     public int indexOfValue(int value) {
172         for (int i = 0; i < mSize; i++)
173             if (mValues[i] == value)
174                 return i;
175 
176         return -1;
177     }
178 
179     /**
180      * Removes all key-value mappings from this SparseIntArray.
181      */
clear()182     public void clear() {
183         mSize = 0;
184     }
185 
186     /**
187      * Puts a key/value pair into the array, optimizing for the case where
188      * the key is greater than all existing keys in the array.
189      */
append(int key, int value)190     public void append(int key, int value) {
191         if (mSize != 0 && key <= mKeys[mSize - 1]) {
192             put(key, value);
193             return;
194         }
195 
196         int pos = mSize;
197         if (pos >= mKeys.length) {
198             int n = ArrayUtils.idealIntArraySize(pos + 1);
199 
200             int[] nkeys = new int[n];
201             int[] nvalues = new int[n];
202 
203             // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
204             System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
205             System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
206 
207             mKeys = nkeys;
208             mValues = nvalues;
209         }
210 
211         mKeys[pos] = key;
212         mValues[pos] = value;
213         mSize = pos + 1;
214     }
215 
binarySearch(int[] a, int start, int len, int key)216     private static int binarySearch(int[] a, int start, int len, int key) {
217         int high = start + len, low = start - 1, guess;
218 
219         while (high - low > 1) {
220             guess = (high + low) / 2;
221 
222             if (a[guess] < key)
223                 low = guess;
224             else
225                 high = guess;
226         }
227 
228         if (high == start + len)
229             return ~(start + len);
230         else if (a[high] == key)
231             return high;
232         else
233             return ~high;
234     }
235 
checkIntegrity()236     private void checkIntegrity() {
237         for (int i = 1; i < mSize; i++) {
238             if (mKeys[i] <= mKeys[i - 1]) {
239                 for (int j = 0; j < mSize; j++) {
240                     Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
241                 }
242 
243                 throw new RuntimeException();
244             }
245         }
246     }
247 
248     private int[] mKeys;
249     private int[] mValues;
250     private int mSize;
251 }
252