1 /*
2  * Copyright (C) 2023 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 com.android.server.permission.access.immutable
18 
19 import android.util.SparseArray
20 
21 /** Immutable map with index-based access and [Int] keys. */
22 sealed class IntMap<T>(internal val array: SparseArray<T>) : Immutable<MutableIntMap<T>> {
23     val size: Int
24         get() = array.size()
25 
isEmptynull26     fun isEmpty(): Boolean = array.size() == 0
27 
28     operator fun contains(key: Int): Boolean = array.contains(key)
29 
30     operator fun get(key: Int): T? = array.get(key)
31 
32     fun indexOfKey(key: Int): Int = array.indexOfKey(key)
33 
34     fun keyAt(index: Int): Int = array.keyAt(index)
35 
36     fun valueAt(index: Int): T = array.valueAt(index)
37 
38     override fun toMutable(): MutableIntMap<T> = MutableIntMap(this)
39 
40     override fun toString(): String = array.toString()
41 }
42 
43 /** Mutable map with index-based access and [Int] keys. */
44 class MutableIntMap<T>(array: SparseArray<T> = SparseArray()) : IntMap<T>(array) {
45     constructor(intMap: IntMap<T>) : this(intMap.array.clone())
46 
47     fun put(key: Int, value: T): T? = array.putReturnOld(key, value)
48 
49     fun remove(key: Int): T? = array.removeReturnOld(key).also { array.gc() }
50 
51     fun clear() {
52         array.clear()
53     }
54 
55     fun putAt(index: Int, value: T): T = array.setValueAtReturnOld(index, value)
56 
57     fun removeAt(index: Int): T = array.removeAtReturnOld(index).also { array.gc() }
58 }
59 
putReturnOldnull60 internal fun <T> SparseArray<T>.putReturnOld(key: Int, value: T): T? {
61     val index = indexOfKey(key)
62     return if (index >= 0) {
63         val oldValue = valueAt(index)
64         setValueAt(index, value)
65         oldValue
66     } else {
67         put(key, value)
68         null
69     }
70 }
71 
72 // SparseArray.removeReturnOld() is @hide, so a backup once we move to APIs.
73 @Suppress("EXTENSION_SHADOWED_BY_MEMBER")
removeReturnOldnull74 internal fun <T> SparseArray<T>.removeReturnOld(key: Int): T? {
75     val index = indexOfKey(key)
76     return if (index >= 0) {
77         val oldValue = valueAt(index)
78         removeAt(index)
79         oldValue
80     } else {
81         null
82     }
83 }
84 
setValueAtReturnOldnull85 internal fun <T> SparseArray<T>.setValueAtReturnOld(index: Int, value: T): T {
86     val oldValue = valueAt(index)
87     setValueAt(index, value)
88     return oldValue
89 }
90 
removeAtReturnOldnull91 internal fun <T> SparseArray<T>.removeAtReturnOld(index: Int): T {
92     val oldValue = valueAt(index)
93     removeAt(index)
94     return oldValue
95 }
96 
gcnull97 internal fun <T> SparseArray<T>.gc() {
98     size()
99 }
100