• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 package org.jf.util;
33 
34 /**
35  * SparseIntArrays map integers to integers.  Unlike a normal array of integers,
36  * there can be gaps in the indices.  It is intended to be more efficient
37  * than using a HashMap to map Integers to Integers.
38  */
39 public class SparseIntArray {
40     /**
41      * Creates a new SparseIntArray containing no mappings.
42      */
SparseIntArray()43     public SparseIntArray() {
44         this(10);
45     }
46 
47     /**
48      * Creates a new SparseIntArray containing no mappings that will not
49      * require any additional memory allocation to store the specified
50      * number of mappings.
51      */
SparseIntArray(int initialCapacity)52     public SparseIntArray(int initialCapacity) {
53         mKeys = new int[initialCapacity];
54         mValues = new int[initialCapacity];
55         mSize = 0;
56     }
57 
58     /**
59      * Gets the int mapped from the specified key, or <code>0</code>
60      * if no such mapping has been made.
61      */
get(int key)62     public int get(int key) {
63         return get(key, 0);
64     }
65 
66     /**
67      * Gets the int mapped from the specified key, or the specified value
68      * if no such mapping has been made.
69      */
get(int key, int valueIfKeyNotFound)70     public int get(int key, int valueIfKeyNotFound) {
71         int i = binarySearch(mKeys, 0, mSize, key);
72 
73         if (i < 0) {
74             return valueIfKeyNotFound;
75         } else {
76             return mValues[i];
77         }
78     }
79 
80     /**
81      * Gets the int mapped from the specified key, or if not present, the
82      * closest key that is less than the specified key.
83      */
getClosestSmaller(int key)84     public int getClosestSmaller(int key) {
85         int i = binarySearch(mKeys, 0, mSize, key);
86 
87         if (i < 0) {
88             i = ~i;
89             if (i > 0) {
90                 i--;
91             }
92             return mValues[i];
93         } else {
94             return mValues[i];
95         }
96     }
97 
98     /**
99      * Removes the mapping from the specified key, if there was any.
100      */
delete(int key)101     public void delete(int key) {
102         int i = binarySearch(mKeys, 0, mSize, key);
103 
104         if (i >= 0) {
105             removeAt(i);
106         }
107     }
108 
109     /**
110      * Removes the mapping at the given index.
111      */
removeAt(int index)112     public void removeAt(int index) {
113         System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
114         System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1));
115         mSize--;
116     }
117 
118     /**
119      * Adds a mapping from the specified key to the specified value,
120      * replacing the previous mapping from the specified key if there
121      * was one.
122      */
put(int key, int value)123     public void put(int key, int value) {
124         int i = binarySearch(mKeys, 0, mSize, key);
125 
126         if (i >= 0) {
127             mValues[i] = value;
128         } else {
129             i = ~i;
130 
131             if (mSize >= mKeys.length) {
132                 int n = Math.max(mSize + 1, mKeys.length * 2);
133 
134                 int[] nkeys = new int[n];
135                 int[] nvalues = new int[n];
136 
137                 // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
138                 System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
139                 System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
140 
141                 mKeys = nkeys;
142                 mValues = nvalues;
143             }
144 
145             if (mSize - i != 0) {
146                 // Log.e("SparseIntArray", "move " + (mSize - i));
147                 System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
148                 System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
149             }
150 
151             mKeys[i] = key;
152             mValues[i] = value;
153             mSize++;
154         }
155     }
156 
157     /**
158      * Returns the number of key-value mappings that this SparseIntArray
159      * currently stores.
160      */
size()161     public int size() {
162         return mSize;
163     }
164 
165     /**
166      * Given an index in the range <code>0...size()-1</code>, returns
167      * the key from the <code>index</code>th key-value mapping that this
168      * SparseIntArray stores.
169      */
keyAt(int index)170     public int keyAt(int index) {
171         return mKeys[index];
172     }
173 
174     /**
175      * Given an index in the range <code>0...size()-1</code>, returns
176      * the value from the <code>index</code>th key-value mapping that this
177      * SparseIntArray stores.
178      */
valueAt(int index)179     public int valueAt(int index) {
180         return mValues[index];
181     }
182 
183     /**
184      * Returns the index for which {@link #keyAt} would return the
185      * specified key, or a negative number if the specified
186      * key is not mapped.
187      */
indexOfKey(int key)188     public int indexOfKey(int key) {
189         return binarySearch(mKeys, 0, mSize, key);
190     }
191 
192     /**
193      * Returns an index for which {@link #valueAt} would return the
194      * specified key, or a negative number if no keys map to the
195      * specified value.
196      * Beware that this is a linear search, unlike lookups by key,
197      * and that multiple keys can map to the same value and this will
198      * find only one of them.
199      */
indexOfValue(int value)200     public int indexOfValue(int value) {
201         for (int i = 0; i < mSize; i++)
202             if (mValues[i] == value)
203                 return i;
204 
205         return -1;
206     }
207 
208     /**
209      * Removes all key-value mappings from this SparseIntArray.
210      */
clear()211     public void clear() {
212         mSize = 0;
213     }
214 
215     /**
216      * Puts a key/value pair into the array, optimizing for the case where
217      * the key is greater than all existing keys in the array.
218      */
append(int key, int value)219     public void append(int key, int value) {
220         if (mSize != 0 && key <= mKeys[mSize - 1]) {
221             put(key, value);
222             return;
223         }
224 
225         int pos = mSize;
226         if (pos >= mKeys.length) {
227             int n = Math.max(pos + 1, mKeys.length * 2);
228 
229             int[] nkeys = new int[n];
230             int[] nvalues = new int[n];
231 
232             // Log.e("SparseIntArray", "grow " + mKeys.length + " to " + n);
233             System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
234             System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
235 
236             mKeys = nkeys;
237             mValues = nvalues;
238         }
239 
240         mKeys[pos] = key;
241         mValues[pos] = value;
242         mSize = pos + 1;
243     }
244 
binarySearch(int[] a, int start, int len, int key)245     private static int binarySearch(int[] a, int start, int len, int key) {
246         int high = start + len, low = start - 1, guess;
247 
248         while (high - low > 1) {
249             guess = (high + low) / 2;
250 
251             if (a[guess] < key)
252                 low = guess;
253             else
254                 high = guess;
255         }
256 
257         if (high == start + len)
258             return ~(start + len);
259         else if (a[high] == key)
260             return high;
261         else
262             return ~high;
263     }
264 
265     private int[] mKeys;
266     private int[] mValues;
267     private int mSize;
268 }
269