1 /*
2  * Copyright 2025 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.tracing.driver
18 
19 /**
20  * An Object pool that keeps track of scrap objects in a fixed size [ArrayDeque].
21  *
22  * @param size represents the size of the Object pool.
23  * @param factory is a function that can be used to create the instances of the Object for the pool.
24  * @param T represents an object that be re-used.
25  */
26 internal class Pool<T>(
27     private val size: Int,
28     private val isDebug: Boolean,
29     private val factory: (owner: Pool<T>) -> T
30 ) {
31     private var counter: AtomicLong? = null
32 
33     init {
34         if (isDebug) {
35             counter = AtomicLong(0L)
36         }
37     }
38 
39     // This class is intentionally lock free.
40     // This is because, the only place where we recycle objects in the pool is in the TraceSink
41     // and that effectively behaves as-if it were single threaded.
42     private val scrapPool: ArrayDeque<T> = ArrayDeque(size)
43 
44     init {
45         // Eagerly create the objects for the pool
<lambda>null46         repeat(size) { scrapPool.addLast(factory(this)) }
47     }
48 
49     /** Obtain an instance of the object from the pool. */
obtainnull50     internal fun obtain(): T {
51         if (isDebug) {
52             counter?.incrementAndGet()
53         }
54         return scrapPool.removeFirstOrNull() ?: factory(this)
55     }
56 
releasenull57     internal fun release(element: T) {
58         if (isDebug) {
59             counter?.decrement()
60         }
61         if (scrapPool.size < size) {
62             scrapPool.addFirst(element)
63         }
64     }
65 
countnull66     internal fun count(): Long {
67         return counter?.get() ?: 0L
68     }
69 }
70