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