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 the data for the key and mapKey, if there was any. 66 * 67 * @return Returns the value that was stored under the keys, or null if there was none. 68 */ 69 @Nullable delete(int key, @NonNull K mapKey)70 public V delete(int key, @NonNull K mapKey) { 71 ArrayMap<K, V> data = mData.get(key); 72 if (data != null) { 73 return data.remove(mapKey); 74 } 75 return null; 76 } 77 78 /** 79 * Get the value associated with the int-K pair. 80 */ 81 @Nullable get(int key, @NonNull K mapKey)82 public V get(int key, @NonNull K mapKey) { 83 ArrayMap<K, V> data = mData.get(key); 84 if (data != null) { 85 return data.get(mapKey); 86 } 87 return null; 88 } 89 90 /** 91 * Returns the value to which the specified key and mapKey are mapped, or defaultValue if this 92 * map contains no mapping for them. 93 */ 94 @Nullable getOrDefault(int key, @NonNull K mapKey, V defaultValue)95 public V getOrDefault(int key, @NonNull K mapKey, V defaultValue) { 96 if (mData.contains(key)) { 97 ArrayMap<K, V> data = mData.get(key); 98 if (data != null && data.containsKey(mapKey)) { 99 return data.get(mapKey); 100 } 101 } 102 return defaultValue; 103 } 104 105 /** @see SparseArray#indexOfKey */ indexOfKey(int key)106 public int indexOfKey(int key) { 107 return mData.indexOfKey(key); 108 } 109 110 /** 111 * Returns the index of the mapKey. 112 * 113 * @see SparseArray#indexOfKey 114 */ indexOfKey(int key, @NonNull K mapKey)115 public int indexOfKey(int key, @NonNull K mapKey) { 116 ArrayMap<K, V> data = mData.get(key); 117 if (data != null) { 118 return data.indexOfKey(mapKey); 119 } 120 return -1; 121 } 122 123 /** Returns the key at the given index. */ keyAt(int index)124 public int keyAt(int index) { 125 return mData.keyAt(index); 126 } 127 128 /** Returns the map's key at the given mapIndex for the given keyIndex. */ 129 @NonNull keyAt(int keyIndex, int mapIndex)130 public K keyAt(int keyIndex, int mapIndex) { 131 return mData.valueAt(keyIndex).keyAt(mapIndex); 132 } 133 134 /** Returns the size of the outer array. */ numMaps()135 public int numMaps() { 136 return mData.size(); 137 } 138 139 /** Returns the number of elements in the map of the given key. */ numElementsForKey(int key)140 public int numElementsForKey(int key) { 141 ArrayMap<K, V> data = mData.get(key); 142 return data == null ? 0 : data.size(); 143 } 144 145 /** Returns the value V at the given key and map index. */ 146 @Nullable valueAt(int keyIndex, int mapIndex)147 public V valueAt(int keyIndex, int mapIndex) { 148 return mData.valueAt(keyIndex).valueAt(mapIndex); 149 } 150 151 /** Iterate through all int-K pairs and operate on all of the values. */ forEach(@onNull Consumer<V> consumer)152 public void forEach(@NonNull Consumer<V> consumer) { 153 for (int i = numMaps() - 1; i >= 0; --i) { 154 ArrayMap<K, V> data = mData.valueAt(i); 155 for (int j = data.size() - 1; j >= 0; --j) { 156 consumer.accept(data.valueAt(j)); 157 } 158 } 159 } 160 } 161