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
18009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powellpackage android.support.v4.util;
19009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
20009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
21009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell/**
226db4c676e03b3637cc0182ba5475d47e8be62c92Aurimas Liutikas * Helper class for creating pools of objects. An example use looks like this:
23009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * <pre>
24009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * public class MyPooledClass {
25009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
26009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     private static final SynchronizedPool<MyPooledClass> sPool =
27009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *             new SynchronizedPool<MyPooledClass>(10);
28009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
29009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     public static MyPooledClass obtain() {
30009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *         MyPooledClass instance = sPool.acquire();
31009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *         return (instance != null) ? instance : new MyPooledClass();
32009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     }
33009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
34009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     public void recycle() {
35009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *          // Clear state if needed.
36009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *          sPool.release(this);
37009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     }
38009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
39009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *     . . .
40009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * }
41009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell * </pre>
42009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell *
43009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell */
44009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powellpublic final class Pools {
45009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
46009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    /**
47009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * Interface for managing a pool of objects.
48009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     *
49009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * @param <T> The pooled type.
50009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     */
51009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    public static interface Pool<T> {
52009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
53009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /**
54009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @return An instance from the pool if such, null otherwise.
55009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         */
56009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public T acquire();
57009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
58009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /**
59009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * Release an instance to the pool.
60009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
61009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @param instance The instance to release.
62009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @return Whether the instance was put in the pool.
63009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
64009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @throws IllegalStateException If the instance is already in the pool.
65009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         */
66009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public boolean release(T instance);
67009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    }
68009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
69009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    private Pools() {
70009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /* do nothing - hiding constructor */
71009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    }
72009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
73009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    /**
74009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * Simple (non-synchronized) pool of objects.
75009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     *
76009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * @param <T> The pooled type.
77009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     */
78009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    public static class SimplePool<T> implements Pool<T> {
79009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        private final Object[] mPool;
80009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
81009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        private int mPoolSize;
82009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
83009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /**
84009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * Creates a new instance.
85009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
86009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @param maxPoolSize The max pool size.
87009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
88009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @throws IllegalArgumentException If the max pool size is less than zero.
89009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         */
90009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public SimplePool(int maxPoolSize) {
91009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            if (maxPoolSize <= 0) {
92009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                throw new IllegalArgumentException("The max pool size must be > 0");
93009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
94009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            mPool = new Object[maxPoolSize];
95009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
96009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
97009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @Override
98009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @SuppressWarnings("unchecked")
99009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public T acquire() {
100009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            if (mPoolSize > 0) {
101009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                final int lastPooledIndex = mPoolSize - 1;
102009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                T instance = (T) mPool[lastPooledIndex];
103009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                mPool[lastPooledIndex] = null;
104009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                mPoolSize--;
105009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                return instance;
106009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
107009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            return null;
108009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
109009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
110009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @Override
111009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public boolean release(T instance) {
112009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            if (isInPool(instance)) {
113009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                throw new IllegalStateException("Already in the pool!");
114009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
115009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            if (mPoolSize < mPool.length) {
116009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                mPool[mPoolSize] = instance;
117009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                mPoolSize++;
118009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                return true;
119009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
120009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            return false;
121009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
122009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
123009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        private boolean isInPool(T instance) {
124009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            for (int i = 0; i < mPoolSize; i++) {
125009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                if (mPool[i] == instance) {
126009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                    return true;
127009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                }
128009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
129009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            return false;
130009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
131009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    }
132009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
133009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    /**
134009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * Synchronized) pool of objects.
135009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     *
136009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     * @param <T> The pooled type.
137009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell     */
138009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    public static class SynchronizedPool<T> extends SimplePool<T> {
139009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        private final Object mLock = new Object();
140009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
141009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        /**
142009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * Creates a new instance.
143009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
144009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @param maxPoolSize The max pool size.
145009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         *
146009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         * @throws IllegalArgumentException If the max pool size is less than zero.
147009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell         */
148009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public SynchronizedPool(int maxPoolSize) {
149009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            super(maxPoolSize);
150009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
151009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
152009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @Override
153009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public T acquire() {
154009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            synchronized (mLock) {
155009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                return super.acquire();
156009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
157009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
158009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell
159009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        @Override
160009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        public boolean release(T element) {
161009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            synchronized (mLock) {
162009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell                return super.release(element);
163009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell            }
164009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell        }
165009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell    }
166009b4ef9d97e1cc237477e3284fc305bb1438cc9Adam Powell}
167