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 /** 20 * Wrapper class for reference to a mutable data structure instance. 21 * 22 * This class encapsulates the logic to mutate/copy a mutable data structure instance and update the 23 * reference to the new mutated instance. It also remembers the mutated instance so that it can be 24 * reused during further mutations. 25 * 26 * Instances of this class should be kept private within a data structure, with the [get] method 27 * exposed on the immutable interface of the data structure as a `getFoo` method, and the [mutate] 28 * method exposed on the mutable interface of the data structure as a `mutateFoo` method. When the 29 * data structure is mutated/copied, a new instance of this class should be obtained with 30 * [toImmutable], which makes the wrapped reference immutable-only again and thus prevents further 31 * modifications to a data structure accessed with its immutable interface. 32 * 33 * @see MutableIndexedReferenceMap 34 * @see MutableIntReferenceMap 35 */ 36 class MutableReference<I : Immutable<M>, M : I> 37 private constructor(private var immutable: I, private var mutable: M?) { 38 constructor(mutable: M) : this(mutable, mutable) 39 40 /** Return an immutable reference to the wrapped mutable data structure. */ getnull41 fun get(): I = immutable 42 43 /** 44 * Make the wrapped mutable data structure mutable, by either calling [Immutable.toMutable] and 45 * replacing the wrapped reference with its result, or reusing the existing reference if it's 46 * already mutable. 47 */ 48 fun mutate(): M { 49 mutable?.let { 50 return it 51 } 52 return immutable.toMutable().also { 53 immutable = it 54 mutable = it 55 } 56 } 57 58 /** 59 * Create a new [MutableReference] instance with the wrapped mutable data structure being 60 * immutable-only again. 61 */ toImmutablenull62 fun toImmutable(): MutableReference<I, M> = MutableReference(immutable, null) 63 64 override fun equals(other: Any?): Boolean { 65 if (this === other) { 66 return true 67 } 68 if (javaClass != other?.javaClass) { 69 return false 70 } 71 other as MutableReference<*, *> 72 return immutable == other.immutable 73 } 74 hashCodenull75 override fun hashCode(): Int = immutable.hashCode() 76 } 77