• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.TestApi;
22 
23 import java.util.function.Consumer;
24 
25 /**
26  * A sparse array of ArrayMaps, which is suitable for holding (userId, packageName)->object
27  * associations.
28  *
29  * @param <K> Any class
30  * @param <V> Any class
31  * @hide
32  */
33 @TestApi
34 public class SparseArrayMap<K, V> {
35     private final SparseArray<ArrayMap<K, V>> mData = new SparseArray<>();
36 
37     /** Add an entry associating obj with the int-K pair. */
add(int key, @NonNull K mapKey, @Nullable V obj)38     public void add(int key, @NonNull K mapKey, @Nullable V obj) {
39         ArrayMap<K, V> data = mData.get(key);
40         if (data == null) {
41             data = new ArrayMap<>();
42             mData.put(key, data);
43         }
44         data.put(mapKey, obj);
45     }
46 
47     /** Remove all entries from the map. */
clear()48     public void clear() {
49         for (int i = 0; i < mData.size(); ++i) {
50             mData.valueAt(i).clear();
51         }
52     }
53 
54     /** Return true if the structure contains an explicit entry for the int-K pair. */
contains(int key, @NonNull K mapKey)55     public boolean contains(int key, @NonNull K mapKey) {
56         return mData.contains(key) && mData.get(key).containsKey(mapKey);
57     }
58 
59     /** Removes all the data for the key, if there was any. */
delete(int key)60     public void delete(int key) {
61         mData.delete(key);
62     }
63 
64     /**
65      * Removes all the data for the keyIndex, if there was any.
66      * @hide
67      */
deleteAt(int keyIndex)68     public void deleteAt(int keyIndex) {
69         mData.removeAt(keyIndex);
70     }
71 
72     /**
73      * Removes the data for the key and mapKey, if there was any.
74      *
75      * @return Returns the value that was stored under the keys, or null if there was none.
76      */
77     @Nullable
delete(int key, @NonNull K mapKey)78     public V delete(int key, @NonNull K mapKey) {
79         ArrayMap<K, V> data = mData.get(key);
80         if (data != null) {
81             return data.remove(mapKey);
82         }
83         return null;
84     }
85 
86     /**
87      * Get the value associated with the int-K pair.
88      */
89     @Nullable
get(int key, @NonNull K mapKey)90     public V get(int key, @NonNull K mapKey) {
91         ArrayMap<K, V> data = mData.get(key);
92         if (data != null) {
93             return data.get(mapKey);
94         }
95         return null;
96     }
97 
98     /**
99      * Returns the value to which the specified key and mapKey are mapped, or defaultValue if this
100      * map contains no mapping for them.
101      */
102     @Nullable
getOrDefault(int key, @NonNull K mapKey, V defaultValue)103     public V getOrDefault(int key, @NonNull K mapKey, V defaultValue) {
104         if (mData.contains(key)) {
105             ArrayMap<K, V> data = mData.get(key);
106             if (data != null && data.containsKey(mapKey)) {
107                 return data.get(mapKey);
108             }
109         }
110         return defaultValue;
111     }
112 
113     /** @see SparseArray#indexOfKey */
indexOfKey(int key)114     public int indexOfKey(int key) {
115         return mData.indexOfKey(key);
116     }
117 
118     /**
119      * Returns the index of the mapKey.
120      *
121      * @see SparseArray#indexOfKey
122      */
indexOfKey(int key, @NonNull K mapKey)123     public int indexOfKey(int key, @NonNull K mapKey) {
124         ArrayMap<K, V> data = mData.get(key);
125         if (data != null) {
126             return data.indexOfKey(mapKey);
127         }
128         return -1;
129     }
130 
131     /** Returns the key at the given index. */
keyAt(int index)132     public int keyAt(int index) {
133         return mData.keyAt(index);
134     }
135 
136     /** Returns the map's key at the given mapIndex for the given keyIndex. */
137     @NonNull
keyAt(int keyIndex, int mapIndex)138     public K keyAt(int keyIndex, int mapIndex) {
139         return mData.valueAt(keyIndex).keyAt(mapIndex);
140     }
141 
142     /** Returns the size of the outer array. */
numMaps()143     public int numMaps() {
144         return mData.size();
145     }
146 
147     /** Returns the number of elements in the map of the given key. */
numElementsForKey(int key)148     public int numElementsForKey(int key) {
149         ArrayMap<K, V> data = mData.get(key);
150         return data == null ? 0 : data.size();
151     }
152 
153     /**
154      * Returns the number of elements in the map of the given keyIndex.
155      * @hide
156      */
numElementsForKeyAt(int keyIndex)157     public int numElementsForKeyAt(int keyIndex) {
158         ArrayMap<K, V> data = mData.valueAt(keyIndex);
159         return data == null ? 0 : data.size();
160     }
161 
162     /** Returns the value V at the given key and map index. */
163     @Nullable
valueAt(int keyIndex, int mapIndex)164     public V valueAt(int keyIndex, int mapIndex) {
165         return mData.valueAt(keyIndex).valueAt(mapIndex);
166     }
167 
168     /** Iterate through all int-K pairs and operate on all of the values. */
forEach(@onNull Consumer<V> consumer)169     public void forEach(@NonNull Consumer<V> consumer) {
170         for (int i = numMaps() - 1; i >= 0; --i) {
171             ArrayMap<K, V> data = mData.valueAt(i);
172             for (int j = data.size() - 1; j >= 0; --j) {
173                 consumer.accept(data.valueAt(j));
174             }
175         }
176     }
177 
178     /**
179      * @param <K> Any class
180      * @param <V> Any class
181      * @hide
182      */
183     public interface TriConsumer<K, V> {
184         /** Consume the int-K-V tuple. */
accept(int key, K mapKey, V value)185         void accept(int key, K mapKey, V value);
186     }
187 
188     /**
189      * Iterate through all int-K pairs and operate on all of the values.
190      * @hide
191      */
forEach(@onNull TriConsumer<K, V> consumer)192     public void forEach(@NonNull TriConsumer<K, V> consumer) {
193         for (int iIdx = numMaps() - 1; iIdx >= 0; --iIdx) {
194             final int i = mData.keyAt(iIdx);
195             final ArrayMap<K, V> data = mData.valueAt(iIdx);
196             for (int kIdx = data.size() - 1; kIdx >= 0; --kIdx) {
197                 consumer.accept(i, data.keyAt(kIdx), data.valueAt(kIdx));
198             }
199         }
200     }
201 }
202