content: /*
   * Copyright 2013 Hannes Janetzek
   *
   * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
   *
   * This program is free software: you can redistribute it and/or modify it under the
   * terms of the GNU Lesser General Public License as published by the Free Software
   * Foundation, either version 3 of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful, but WITHOUT ANY
   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
   * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License along with
   * this program. If not, see <http://www.gnu.org/licenses/>.
   */
  package org.oscim.utils.pool;
  
  import javax.annotation.CheckReturnValue;
  
  @SuppressWarnings({"rawtypes", "unchecked"})
  public abstract class SyncPool<T extends Inlist<?>> {
      protected final int mMaxFill;
      protected final boolean mClearItems;
  
      protected int mFill;
      protected T mPool;
  
      public SyncPool(int maxItemsInPool) {
          this(maxItemsInPool, true);
      }
  
      public SyncPool(int maxItemsInPool, boolean clearItems) {
          mMaxFill = maxItemsInPool;
          mFill = 0;
          mClearItems = clearItems;
      }
  
      public int getFill() {
          return mFill;
      }
  
      /**
       * To be implemented by subclass.
       *
       * @param items number of initial items
       */
      public void init(int items) {
          mFill = 0;
          mPool = null;
      }
  
      public synchronized void clear() {
          while (mPool != null) {
              freeItem(mPool);
              mPool = (T) mPool.next;
          }
      }
  
      /**
       * @param item set initial state
       * @return 'true' when item should be added back to pool,
       * 'false' when freeItem should be called.
       */
      protected boolean clearItem(T item) {
          return true;
      }
  
      /**
       * @param item release resources
       */
      protected void freeItem(T item) {
  
      }
  
      /**
       * Creates the item. To be implemented by subclass.
       *
       * @return the item
       */
      protected abstract T createItem();
  
      /**
       * Release 'item' to pool.
       * <p/>
       * Usage item = pool.release(item), to ensure to not keep a reference to
       * item!
       */
      @CheckReturnValue
      public T release(T item) {
          if (item == null)
              return null;
  
          if (mClearItems && !clearItem(item)) {
              // dont add back to pool
              freeItem(item);
              return null;
          }
          if (mFill < mMaxFill) {
              synchronized (this) {
                  mFill++;
  
                  ((Inlist) item).next = (T) mPool;
                  mPool = item;
              }
          } else if (mClearItems) {
              freeItem(item);
          }
          return null;
      }
  
      /**
       * Release 'list' to pool.
       * <p/>
       * Usage list = pool.releaseAll(list), to ensure to not keep a reference to
       * list!
       */
      @CheckReturnValue
      public T releaseAll(T item) {
          if (item == null)
              return null;
  
          if (mFill > mMaxFill) {
              while (item != null) {
                  if (mClearItems) {
                      clearItem(item);
                      freeItem(item);
                  }
                  item = (T) item.next;
              }
              return null;
          }
  
          synchronized (this) {
              while (item != null) {
                  T next = (T) item.next;
  
                  if (mClearItems && !clearItem(item)) {
                      // dont add back to pool
                      freeItem(item);
                      item = next;
                      continue;
                  }
  
                  mFill++;
  
                  ((Inlist) item).next = (T) mPool;
                  mPool = item;
  
                  item = next;
              }
          }
          return null;
      }
  
      /**
       * Gets an 'item' from pool, if pool is empty a new
       * item will be created by createItem().
       *
       * @return the item
       */
      public T get() {
  
          synchronized (this) {
              if (mPool == null) {
                  return createItem();
              }
  
              mFill--;
  
              T ret = mPool;
              mPool = (T) mPool.next;
  
              ret.next = null;
              return ret;
          }
      }
  }
  