1009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell/*
2009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * Copyright (C) 2013 The Android Open Source Project
3009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
4009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * Licensed under the Apache License, Version 2.0 (the "License");
5009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * you may not use this file except in compliance with the License.
6009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * You may obtain a copy of the License at
7009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
8009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *      http://www.apache.org/licenses/LICENSE-2.0
9009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
10009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * Unless required by applicable law or agreed to in writing, software
11009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * distributed under the License is distributed on an "AS IS" BASIS,
12009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * See the License for the specific language governing permissions and
14009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * limitations under the License.
15009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell */
16009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
17009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
18ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.core.util;
19009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
20009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
21ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.NonNull;
22ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable;
239f498146df152fc38a4004cb7aefdd2d71943205Jake Wharton
24009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell/**
256db4c676e03b3637cc0182ba5475d47e8be62c92Aurimas Liutikas * Helper class for creating pools of objects. An example use looks like this:
26009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * <pre>
27009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * public class MyPooledClass {
28009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
29009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     private static final SynchronizedPool<MyPooledClass> sPool =
30009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *             new SynchronizedPool<MyPooledClass>(10);
31009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
32009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     public static MyPooledClass obtain() {
33009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *         MyPooledClass instance = sPool.acquire();
34009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *         return (instance != null) ? instance : new MyPooledClass();
35009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     }
36009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
37009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     public void recycle() {
38009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *          // Clear state if needed.
39009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *          sPool.release(this);
40009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     }
41009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
42009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     . . .
43009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * }
44009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * </pre>
45009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
46009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell */
47009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powellpublic final class Pools {
48009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
49009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    /**
50009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * Interface for managing a pool of objects.
51009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     *
52009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * @param <T> The pooled type.
53009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     */
545211222f71426ccfc1f2cca9f5f6bb89c61c9ed5Jake Wharton    public interface Pool<T> {
55009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
56009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /**
57009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @return An instance from the pool if such, null otherwise.
58009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         */
599f498146df152fc38a4004cb7aefdd2d71943205Jake Wharton        @Nullable
605211222f71426ccfc1f2cca9f5f6bb89c61c9ed5Jake Wharton        T acquire();
61009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
62009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /**
63009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * Release an instance to the pool.
64009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
65009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @param instance The instance to release.
66009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @return Whether the instance was put in the pool.
67009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
68009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @throws IllegalStateException If the instance is already in the pool.
69009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         */
705211222f71426ccfc1f2cca9f5f6bb89c61c9ed5Jake Wharton        boolean release(@NonNull T instance);
71009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    }
72009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
73009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    private Pools() {
74009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /* do nothing - hiding constructor */
75009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    }
76009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
77009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    /**
78009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * Simple (non-synchronized) pool of objects.
79009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     *
80009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * @param <T> The pooled type.
81009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     */
82009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    public static class SimplePool<T> implements Pool<T> {
83009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        private final Object[] mPool;
84009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
85009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        private int mPoolSize;
86009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
87009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /**
88009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * Creates a new instance.
89009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
90009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @param maxPoolSize The max pool size.
91009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
92009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @throws IllegalArgumentException If the max pool size is less than zero.
93009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         */
94009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public SimplePool(int maxPoolSize) {
95009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            if (maxPoolSize <= 0) {
96009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                throw new IllegalArgumentException("The max pool size must be > 0");
97009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
98009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            mPool = new Object[maxPoolSize];
99009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
100009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
101009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @Override
102009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @SuppressWarnings("unchecked")
103009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public T acquire() {
104009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            if (mPoolSize > 0) {
105009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                final int lastPooledIndex = mPoolSize - 1;
106009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                T instance = (T) mPool[lastPooledIndex];
107009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                mPool[lastPooledIndex] = null;
108009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                mPoolSize--;
109009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                return instance;
110009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
111009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            return null;
112009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
113009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
114009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @Override
1159f498146df152fc38a4004cb7aefdd2d71943205Jake Wharton        public boolean release(@NonNull T instance) {
116009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            if (isInPool(instance)) {
117009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                throw new IllegalStateException("Already in the pool!");
118009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
119009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            if (mPoolSize < mPool.length) {
120009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                mPool[mPoolSize] = instance;
121009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                mPoolSize++;
122009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                return true;
123009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
124009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            return false;
125009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
126009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
1279f498146df152fc38a4004cb7aefdd2d71943205Jake Wharton        private boolean isInPool(@NonNull T instance) {
128009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            for (int i = 0; i < mPoolSize; i++) {
129009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                if (mPool[i] == instance) {
130009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                    return true;
131009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                }
132009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
133009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            return false;
134009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
135009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    }
136009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
137009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    /**
138009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * Synchronized) pool of objects.
139009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     *
140009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * @param <T> The pooled type.
141009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     */
142009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    public static class SynchronizedPool<T> extends SimplePool<T> {
143009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        private final Object mLock = new Object();
144009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
145009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /**
146009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * Creates a new instance.
147009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
148009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @param maxPoolSize The max pool size.
149009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
150009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @throws IllegalArgumentException If the max pool size is less than zero.
151009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         */
152009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public SynchronizedPool(int maxPoolSize) {
153009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            super(maxPoolSize);
154009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
155009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
156009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @Override
157009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public T acquire() {
158009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            synchronized (mLock) {
159009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                return super.acquire();
160009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
161009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
162009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
163009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @Override
1649f498146df152fc38a4004cb7aefdd2d71943205Jake Wharton        public boolean release(@NonNull T element) {
165009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            synchronized (mLock) {
166009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                return super.release(element);
167009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
168009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
169009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    }
170009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell}
171