Pool.java

/*
 * Copyright (c) 2007, 2014, 2018 XStream Committers.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 * 
 * Created on 10. May 2007 by Joerg Schaible
 */
package com.thoughtworks.xstream.core.util;

import java.util.Arrays;


/**
 * A simple pool implementation.
 * 
 * @author Jörg Schaible
 * @author Joe Walnes
 */
public class Pool<T> {

    public interface Factory<T> {
        public T newInstance();
    }

    private final int initialPoolSize;
    private final int maxPoolSize;
    private final Factory<T> factory;
    private transient T[] pool;
    private transient int nextAvailable;

    public Pool(final int initialPoolSize, final int maxPoolSize, final Factory<T> factory) {
        this.initialPoolSize = initialPoolSize;
        this.maxPoolSize = maxPoolSize;
        this.factory = factory;
    }

    @SafeVarargs
    private final T[] newArray(final int capacity, final T... t) {
        return Arrays.copyOf(t, capacity);
    }

    public T fetchFromPool() {
        T result;
        synchronized (this) {
            if (pool == null) {
                final T[] all = newArray(maxPoolSize);
                pool = all;
                for (nextAvailable = initialPoolSize; nextAvailable > 0;) {
                    putInPool(factory.newInstance());
                }
            }
            while (nextAvailable == maxPoolSize) {
                try {
                    wait();
                } catch (final InterruptedException e) {
                    throw new RuntimeException("Interrupted whilst waiting for a free item in the pool: "
                        + e.getMessage());
                }
            }
            result = pool[nextAvailable++];
            if (result == null) {
                result = factory.newInstance();
                putInPool(result);
                ++nextAvailable;
            }
        }
        return result;
    }

    protected void putInPool(final T object) {
        synchronized (this) {
            if (nextAvailable == 0) {
                throw new IllegalStateException("Cannot put more objects than "
                    + maxPoolSize
                    + " elements into this pool");
            }
            pool[--nextAvailable] = object;
            if (object == null) {
                for (int i = maxPoolSize; i > nextAvailable;) {
                    if (pool[--i] != null) {
                        pool[nextAvailable] = pool[i];
                        pool[i] = null;
                        break;
                    }
                }
            }

            notify();
        }
    }
}