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 /**
22  * Immutable map with index-based access, [Int] keys and mutable data structure values.
23  *
24  * @see MutableReference
25  */
26 sealed class IntReferenceMap<I : Immutable<M>, M : I>(
27     internal val array: SparseArray<MutableReference<I, M>>
28 ) : Immutable<MutableIntReferenceMap<I, M>> {
29     val size: Int
30         get() = array.size()
31 
isEmptynull32     fun isEmpty(): Boolean = array.size() == 0
33 
34     operator fun contains(key: Int): Boolean = array.contains(key)
35 
36     @Suppress("ReplaceGetOrSet") operator fun get(key: Int): I? = array.get(key)?.get()
37 
38     fun indexOfKey(key: Int): Int = array.indexOfKey(key)
39 
40     fun keyAt(index: Int): Int = array.keyAt(index)
41 
42     fun valueAt(index: Int): I = array.valueAt(index).get()
43 
44     override fun toMutable(): MutableIntReferenceMap<I, M> = MutableIntReferenceMap(this)
45 
46     override fun toString(): String = array.toString()
47 }
48 
49 /**
50  * Mutable map with index-based access, [Int] keys and mutable data structure values.
51  *
52  * @see MutableReference
53  */
54 class MutableIntReferenceMap<I : Immutable<M>, M : I>(
55     array: SparseArray<MutableReference<I, M>> = SparseArray()
56 ) : IntReferenceMap<I, M>(array) {
57     constructor(
58         intReferenceMap: IntReferenceMap<I, M>
59     ) : this(
60         intReferenceMap.array.clone().apply {
61             for (i in 0 until size()) {
62                 setValueAt(i, valueAt(i).toImmutable())
63             }
64         }
65     )
66 
67     @Suppress("ReplaceGetOrSet") fun mutate(key: Int): M? = array.get(key)?.mutate()
68 
69     fun put(key: Int, value: M): I? = array.putReturnOld(key, MutableReference(value))?.get()
70 
71     fun remove(key: Int): I? = array.removeReturnOld(key).also { array.gc() }?.get()
72 
73     fun clear() {
74         array.clear()
75     }
76 
77     fun mutateAt(index: Int): M = array.valueAt(index).mutate()
78 
79     fun putAt(index: Int, value: M): I =
80         array.setValueAtReturnOld(index, MutableReference(value)).get()
81 
82     fun removeAt(index: Int): I = array.removeAtReturnOld(index).also { array.gc() }.get()
83 }
84