1 /*
2  * Copyright 2021 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 androidx.compose.ui.platform
18 
19 import androidx.compose.runtime.collection.mutableVectorOf
20 import java.lang.ref.Reference
21 import java.lang.ref.ReferenceQueue
22 import java.lang.ref.WeakReference
23 
24 /**
25  * A simple collection that keeps values as [WeakReference]s. Elements are added with [push] and
26  * removed with [pop].
27  */
28 internal class WeakCache<T> {
29     private val values = mutableVectorOf<Reference<T>>()
30     private val referenceQueue = ReferenceQueue<T>()
31 
32     /**
33      * Add [element] to the collection as a [WeakReference]. It will be removed when garbage
34      * collected or from [pop].
35      */
pushnull36     fun push(element: T) {
37         clearWeakReferences()
38         values += WeakReference(element, referenceQueue)
39     }
40 
41     /**
42      * Remove an element from the collection and return it. If no element is available, `null` is
43      * returned.
44      */
popnull45     fun pop(): T? {
46         clearWeakReferences()
47 
48         while (values.isNotEmpty()) {
49             val item = values.removeAt(values.lastIndex).get()
50             if (item != null) {
51                 return item
52             }
53         }
54         return null
55     }
56 
57     /**
58      * The number of elements currently in the collection. This may change between calls if the
59      * references have been garbage collected.
60      */
61     val size: Int
62         get() {
63             clearWeakReferences()
64             return values.size
65         }
66 
clearWeakReferencesnull67     private fun clearWeakReferences() {
68         do {
69             val item: Reference<out T>? = referenceQueue.poll()
70             if (item != null) {
71                 @Suppress("UNCHECKED_CAST") values.remove(item as Reference<T>)
72             }
73         } while (item != null)
74     }
75 }
76