package com.bumptech.glide.util.pool;
import android.support.v4.util.Pools.Pool;
import android.support.v4.util.Pools.SimplePool;
import android.support.v4.util.Pools.SynchronizedPool;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* Provides implementations of {@link Pool} never return {@code null}, log when new instances are
* created, and that can use the {@link com.bumptech.glide.util.pool.FactoryPools.Poolable}
* interface to ensure objects aren't used while inside the pool.
*/
public final class FactoryPools {
private static final String TAG = "FactoryPools";
private static final int DEFAULT_POOL_SIZE = 20;
private static final Resetter<Object> EMPTY_RESETTER = new Resetter<Object>() {
@Override
public void reset(Object object) {
// Do nothing.
}
};
private FactoryPools() { }
/**
* Returns a non-thread safe {@link Pool} that never returns {@code null} from
* {@link Pool#acquire()} and that contains objects of the type created by the given
* {@link Factory} with the given maximum size.
*
* <p>If the pool is empty when {@link Pool#acquire()} is called, the given {@link Factory} will
* be used to create a new instance.
*
* @param <T> The type of object the pool will contains.
*/
public static <T extends Poolable> Pool<T> simple(int size, Factory<T> factory) {
return build(new SimplePool<T>(size), factory);
}
/**
* Returns a new thread safe {@link Pool} that never returns {@code null} from
* {@link Pool#acquire()} and that contains objects of the type created by the given
* {@link Factory} with the given maximum size.
*
* <p>If the pool is empty when {@link Pool#acquire()} is called, the given {@link Factory} will
* be used to create a new instance.
*
* @param <T> The type of object the pool will contains.
*/
public static <T extends Poolable> Pool<T> threadSafe(int size, Factory<T> factory) {
return build(new SynchronizedPool<T>(size), factory);
}
/**
* Returns a new {@link Pool} that never returns {@code null} and that contains {@link List Lists}
* of a specific generic type with a standard maximum size of 20.
*
* <p>If the pool is empty when {@link Pool#acquire()} is called, a new {@link List} will be
* created.
*
* @param <T> The type of object that the {@link List Lists} will contain.
*/
public static <T> Pool<List<T>> threadSafeList() {
return threadSafeList(DEFAULT_POOL_SIZE);
}
/**
* Returns a new thread safe {@link Pool} that never returns {@code null} and that contains
* {@link List Lists} of a specific generic type with the given maximum size.
*
* <p>If the pool is empty when {@link Pool#acquire()} is called, a new {@link List} will be
* created.
*
* @param <T> The type of object that the {@link List Lists} will contain.
*/
public static <T> Pool<List<T>> threadSafeList(int size) {
return build(new SynchronizedPool<List<T>>(size), new Factory<List<T>>() {
@Override
public List<T> create() {
return new ArrayList<>();
}
}, new Resetter<List<T>>() {
@Override
public void reset(List<T> object) {
object.clear();
}
});
}
private static <T extends Poolable> Pool<T> build(Pool<T> pool, Factory<T> factory) {
return build(pool, factory, FactoryPools.<T>emptyResetter());
}
private static <T> Pool<T> build(Pool<T> pool, Factory<T> factory,
Resetter<T> resetter) {
return new FactoryPool<>(pool, factory, resetter);
}
@SuppressWarnings("unchecked")
private static <T> Resetter<T> emptyResetter() {
return (Resetter<T>) EMPTY_RESETTER;
}
/**
* Creates new instances of the given type.
*
* @param <T> The type of Object that will be created.
*/
public interface Factory<T> {
T create();
}
/**
* Resets state when objects are returned to the pool.
*
* @param <T> The type of Object that will be reset.
*/
public interface Resetter<T> {
void reset(T object);
}
/**
* Allows additional verification to catch errors caused by using objects while they are in
* an object pool.
*/
public interface Poolable {
StateVerifier getVerifier();
}
private static final class FactoryPool<T> implements Pool<T> {
private final Factory<T> factory;
private final Resetter<T> resetter;
private final Pool<T> pool;
FactoryPool(Pool<T> pool, Factory<T> factory, Resetter<T> resetter) {
this.pool = pool;
this.factory = factory;
this.resetter = resetter;
}
@Override
public T acquire() {
T result = pool.acquire();
if (result == null) {
result = factory.create();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Created new " + result.getClass());
}
}
if (result instanceof Poolable) {
((Poolable) result).getVerifier().setRecycled(false /*isRecycled*/);
}
return result;
}
@Override
public boolean release(T instance) {
if (instance instanceof Poolable) {
((Poolable) instance).getVerifier().setRecycled(true /*isRecycled*/);
}
resetter.reset(instance);
return pool.release(instance);
}
}
}