1 /*
2  * Copyright (C) 2009 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 android.util;
18 
19 import android.compat.annotation.UnsupportedAppUsage;
20 
21 /**
22  * Helper class for crating pools of objects. An example use looks like this:
23  * <pre>
24  * public class MyPooledClass {
25  *
26  *     private static final SynchronizedPool<MyPooledClass> sPool =
27  *             new SynchronizedPool<MyPooledClass>(10);
28  *
29  *     public static MyPooledClass obtain() {
30  *         MyPooledClass instance = sPool.acquire();
31  *         return (instance != null) ? instance : new MyPooledClass();
32  *     }
33  *
34  *     public void recycle() {
35  *          // Clear state if needed.
36  *          sPool.release(this);
37  *     }
38  *
39  *     . . .
40  * }
41  * </pre>
42  *
43  * @hide
44  */
45 @android.ravenwood.annotation.RavenwoodKeepWholeClass
46 public final class Pools {
47 
48     /**
49      * Interface for managing a pool of objects.
50      *
51      * @param <T> The pooled type.
52      */
53     public static interface Pool<T> {
54 
55         /**
56          * @return An instance from the pool if such, null otherwise.
57          */
58         @UnsupportedAppUsage
acquire()59         public T acquire();
60 
61         /**
62          * Release an instance to the pool.
63          *
64          * @param instance The instance to release.
65          * @return Whether the instance was put in the pool.
66          *
67          * @throws IllegalStateException If the instance is already in the pool.
68          */
69         @UnsupportedAppUsage
release(T instance)70         public boolean release(T instance);
71     }
72 
Pools()73     private Pools() {
74         /* do nothing - hiding constructor */
75     }
76 
77     /**
78      * Simple (non-synchronized) pool of objects.
79      *
80      * @param <T> The pooled type.
81      */
82     public static class SimplePool<T> implements Pool<T> {
83         @UnsupportedAppUsage
84         private final Object[] mPool;
85 
86         private int mPoolSize;
87 
88         /**
89          * Creates a new instance.
90          *
91          * @param maxPoolSize The max pool size.
92          *
93          * @throws IllegalArgumentException If the max pool size is less than zero.
94          */
95         @UnsupportedAppUsage
SimplePool(int maxPoolSize)96         public SimplePool(int maxPoolSize) {
97             if (maxPoolSize <= 0) {
98                 throw new IllegalArgumentException("The max pool size must be > 0");
99             }
100             mPool = new Object[maxPoolSize];
101         }
102 
103         @Override
104         @SuppressWarnings("unchecked")
105         @UnsupportedAppUsage
acquire()106         public T acquire() {
107             if (mPoolSize > 0) {
108                 final int lastPooledIndex = mPoolSize - 1;
109                 T instance = (T) mPool[lastPooledIndex];
110                 mPool[lastPooledIndex] = null;
111                 mPoolSize--;
112                 return instance;
113             }
114             return null;
115         }
116 
117         @Override
118         @UnsupportedAppUsage
release(T instance)119         public boolean release(T instance) {
120             if (isInPool(instance)) {
121                 throw new IllegalStateException("Already in the pool!");
122             }
123             if (mPoolSize < mPool.length) {
124                 mPool[mPoolSize] = instance;
125                 mPoolSize++;
126                 return true;
127             }
128             return false;
129         }
130 
isInPool(T instance)131         private boolean isInPool(T instance) {
132             for (int i = 0; i < mPoolSize; i++) {
133                 if (mPool[i] == instance) {
134                     return true;
135                 }
136             }
137             return false;
138         }
139     }
140 
141     /**
142      * Synchronized pool of objects.
143      *
144      * @param <T> The pooled type.
145      */
146     public static class SynchronizedPool<T> extends SimplePool<T> {
147         private final Object mLock;
148 
149         /**
150          * Creates a new instance.
151          *
152          * @param maxPoolSize The max pool size.
153          * @param lock an optional custom object to synchronize on
154          *
155          * @throws IllegalArgumentException If the max pool size is less than zero.
156          */
SynchronizedPool(int maxPoolSize, Object lock)157         public SynchronizedPool(int maxPoolSize, Object lock) {
158             super(maxPoolSize);
159             mLock = lock;
160         }
161 
162         /** @see #SynchronizedPool(int, Object)  */
163         @UnsupportedAppUsage
SynchronizedPool(int maxPoolSize)164         public SynchronizedPool(int maxPoolSize) {
165             this(maxPoolSize, new Object());
166         }
167 
168         @Override
169         @UnsupportedAppUsage
acquire()170         public T acquire() {
171             synchronized (mLock) {
172                 return super.acquire();
173             }
174         }
175 
176         @Override
177         @UnsupportedAppUsage
release(T element)178         public boolean release(T element) {
179             synchronized (mLock) {
180                 return super.release(element);
181             }
182         }
183     }
184 }
185