• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 /**
20  * SparseDoubleArrays map integers to doubles.  Unlike a normal array of doubles,
21  * there can be gaps in the indices.  It is intended to be more memory efficient
22  * than using a HashMap to map Integers to Doubles, both because it avoids
23  * auto-boxing keys and values and its data structure doesn't rely on an extra entry object
24  * for each mapping.
25  *
26  * <p>Note that this container keeps its mappings in an array data structure,
27  * using a binary search to find keys.  The implementation is not intended to be appropriate for
28  * data structures
29  * that may contain large numbers of items.  It is generally slower than a traditional
30  * HashMap, since lookups require a binary search and adds and removes require inserting
31  * and deleting entries in the array.  For containers holding up to hundreds of items,
32  * the performance difference is not significant, less than 50%.</p>
33  *
34  * <p>It is possible to iterate over the items in this container using
35  * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
36  * <code>keyAt(int)</code> with ascending values of the index will return the
37  * keys in ascending order, or the values corresponding to the keys in ascending
38  * order in the case of <code>valueAt(int)</code>.</p>
39  *
40  * @see SparseLongArray
41  *
42  * @hide
43  */
44 public class SparseDoubleArray implements Cloneable {
45     /**
46      * The int->double map, but storing the doubles as longs using
47      * {@link Double#doubleToRawLongBits(double)}.
48      */
49     private SparseLongArray mValues;
50 
51     /** Creates a new SparseDoubleArray containing no mappings. */
SparseDoubleArray()52     public SparseDoubleArray() {
53         this(10);
54     }
55 
56     /**
57      * Creates a new SparseDoubleArray, containing no mappings, that will not
58      * require any additional memory allocation to store the specified
59      * number of mappings.  If you supply an initial capacity of 0, the
60      * sparse array will be initialized with a light-weight representation
61      * not requiring any additional array allocations.
62      */
SparseDoubleArray(int initialCapacity)63     public SparseDoubleArray(int initialCapacity) {
64         mValues = new SparseLongArray(initialCapacity);
65     }
66 
67     @Override
clone()68     public SparseDoubleArray clone() {
69         SparseDoubleArray clone = null;
70         try {
71             clone = (SparseDoubleArray) super.clone();
72             clone.mValues = mValues.clone();
73         } catch (CloneNotSupportedException cnse) {
74             /* ignore */
75         }
76         return clone;
77     }
78 
79     /**
80      * Gets the double mapped from the specified key, or <code>0</code>
81      * if no such mapping has been made.
82      */
get(int key)83     public double get(int key) {
84         return get(key, 0);
85     }
86 
87     /**
88      * Gets the double mapped from the specified key, or the specified value
89      * if no such mapping has been made.
90      */
get(int key, double valueIfKeyNotFound)91     public double get(int key, double valueIfKeyNotFound) {
92         final int index = mValues.indexOfKey(key);
93         if (index < 0) {
94             return valueIfKeyNotFound;
95         }
96         return valueAt(index);
97     }
98 
99     /**
100      * Adds a mapping from the specified key to the specified value,
101      * replacing the previous mapping from the specified key if there
102      * was one.
103      */
put(int key, double value)104     public void put(int key, double value) {
105         mValues.put(key, Double.doubleToRawLongBits(value));
106     }
107 
108     /**
109      * Adds a mapping from the specified key to the specified value,
110      * <b>adding</b> its value to the previous mapping from the specified key if there
111      * was one.
112      *
113      * <p>This differs from {@link #put} because instead of replacing any previous value, it adds
114      * (in the numerical sense) to it.
115      */
incrementValue(int key, double summand)116     public void incrementValue(int key, double summand) {
117         final double oldValue = get(key);
118         put(key, oldValue + summand);
119     }
120 
121     /** Returns the number of key-value mappings that this SparseDoubleArray currently stores. */
size()122     public int size() {
123         return mValues.size();
124     }
125 
126     /**
127      * Returns the index for which {@link #keyAt} would return the
128      * specified key, or a negative number if the specified
129      * key is not mapped.
130      */
indexOfKey(int key)131     public int indexOfKey(int key) {
132         return mValues.indexOfKey(key);
133     }
134 
135     /**
136      * Given an index in the range <code>0...size()-1</code>, returns
137      * the key from the <code>index</code>th key-value mapping that this
138      * SparseDoubleArray stores.
139      *
140      * @see SparseLongArray#keyAt(int)
141      */
keyAt(int index)142     public int keyAt(int index) {
143         return mValues.keyAt(index);
144     }
145 
146     /**
147      * Given an index in the range <code>0...size()-1</code>, returns
148      * the value from the <code>index</code>th key-value mapping that this
149      * SparseDoubleArray stores.
150      *
151      * @see SparseLongArray#valueAt(int)
152      */
valueAt(int index)153     public double valueAt(int index) {
154         return Double.longBitsToDouble(mValues.valueAt(index));
155     }
156 
157     /**
158      * Given an index in the range <code>0...size()-1</code>, sets a new
159      * value for the <code>index</code>th key-value mapping that this
160      * SparseDoubleArray stores.
161      *
162      * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
163      * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
164      * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
165      * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
166      */
setValueAt(int index, double value)167     public void setValueAt(int index, double value) {
168         mValues.setValueAt(index, Double.doubleToRawLongBits(value));
169     }
170 
171     /**
172      * Removes the mapping at the given index.
173      */
removeAt(int index)174     public void removeAt(int index) {
175         mValues.removeAt(index);
176     }
177 
178     /**
179      * Removes the mapping from the specified key, if there was any.
180      */
delete(int key)181     public void delete(int key) {
182         mValues.delete(key);
183     }
184 
185     /**
186      * Removes all key-value mappings from this SparseDoubleArray.
187      */
clear()188     public void clear() {
189         mValues.clear();
190     }
191 
192     /**
193      * {@inheritDoc}
194      *
195      * <p>This implementation composes a string by iterating over its mappings.
196      */
197     @Override
toString()198     public String toString() {
199         if (size() <= 0) {
200             return "{}";
201         }
202 
203         StringBuilder buffer = new StringBuilder(size() * 34);
204         buffer.append('{');
205         for (int i = 0; i < size(); i++) {
206             if (i > 0) {
207                 buffer.append(", ");
208             }
209             int key = keyAt(i);
210             buffer.append(key);
211             buffer.append('=');
212             double value = valueAt(i);
213             buffer.append(value);
214         }
215         buffer.append('}');
216         return buffer.toString();
217     }
218 }
219