/* 
 | 
 * Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz> 
 | 
 * 
 | 
 * Bullet Continuous Collision Detection and Physics Library 
 | 
 * Copyright (c) 2003-2008 Erwin Coumans  http://www.bulletphysics.com/ 
 | 
 * 
 | 
 * This software is provided 'as-is', without any express or implied warranty. 
 | 
 * In no event will the authors be held liable for any damages arising from 
 | 
 * the use of this software. 
 | 
 *  
 | 
 * Permission is granted to anyone to use this software for any purpose,  
 | 
 * including commercial applications, and to alter it and redistribute it 
 | 
 * freely, subject to the following restrictions: 
 | 
 *  
 | 
 * 1. The origin of this software must not be misrepresented; you must not 
 | 
 *    claim that you wrote the original software. If you use this software 
 | 
 *    in a product, an acknowledgment in the product documentation would be 
 | 
 *    appreciated but is not required. 
 | 
 * 2. Altered source versions must be plainly marked as such, and must not be 
 | 
 *    misrepresented as being the original software. 
 | 
 * 3. This notice may not be removed or altered from any source distribution. 
 | 
 */ 
 | 
  
 | 
package com.bulletphysics.util; 
 | 
  
 | 
import java.lang.reflect.Array; 
 | 
import java.util.Collections; 
 | 
import java.util.Comparator; 
 | 
import java.util.HashMap; 
 | 
import java.util.Map; 
 | 
  
 | 
/** 
 | 
 * Object pool for arrays. 
 | 
 *  
 | 
 * @author jezek2 
 | 
 */ 
 | 
public class ArrayPool<T>  implements java.io.Serializable { 
 | 
  
 | 
    private Class componentType; 
 | 
    private ObjectArrayList list = new ObjectArrayList(); 
 | 
    private Comparator comparator; 
 | 
    private IntValue key = new IntValue(); 
 | 
     
 | 
//        public ArrayPool() 
 | 
//        { 
 | 
//        } 
 | 
    /** 
 | 
     * Creates object pool. 
 | 
     *  
 | 
     * @param componentType 
 | 
     */ 
 | 
    public ArrayPool(Class componentType) { 
 | 
        this.componentType = componentType; 
 | 
         
 | 
        if (componentType == float.class) { 
 | 
            comparator = floatComparator; 
 | 
        } 
 | 
        else if (componentType == int.class) { 
 | 
            comparator = intComparator; 
 | 
        } 
 | 
        else if (!componentType.isPrimitive()) { 
 | 
            comparator = objectComparator; 
 | 
        } 
 | 
        else { 
 | 
            throw new UnsupportedOperationException("unsupported type "+componentType); 
 | 
        } 
 | 
    } 
 | 
     
 | 
    @SuppressWarnings("unchecked") 
 | 
    private T create(int length) { 
 | 
        return (T)Array.newInstance(componentType, length); 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * Returns array of exactly the same length as demanded, or create one if not 
 | 
     * present in the pool. 
 | 
     *  
 | 
     * @param length 
 | 
     * @return array 
 | 
     */ 
 | 
    @SuppressWarnings("unchecked") 
 | 
    public T getFixed(int length) { 
 | 
        key.value = length; 
 | 
        int index = Collections.binarySearch(list, key, comparator); 
 | 
        if (index < 0) { 
 | 
            return create(length); 
 | 
        } 
 | 
        return (T)list.remove(index); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Returns array that has same or greater length, or create one if not present 
 | 
     * in the pool. 
 | 
     *  
 | 
     * @param length the minimum length required 
 | 
     * @return array 
 | 
     */ 
 | 
    @SuppressWarnings("unchecked") 
 | 
    public T getAtLeast(int length) { 
 | 
        key.value = length; 
 | 
        int index = Collections.binarySearch(list, key, comparator); 
 | 
        if (index < 0) { 
 | 
            index = -index - 1; 
 | 
            if (index < list.size()) { 
 | 
                return (T)list.remove(index); 
 | 
            } 
 | 
            else { 
 | 
                return create(length); 
 | 
            } 
 | 
        } 
 | 
        return (T)list.remove(index); 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * Releases array into object pool. 
 | 
     *  
 | 
     * @param array previously obtained array from this pool 
 | 
     */ 
 | 
    @SuppressWarnings("unchecked") 
 | 
    public void release(T array) { 
 | 
        int index = Collections.binarySearch(list, array, comparator); 
 | 
        if (index < 0) index = -index - 1; 
 | 
        list.add(index, array); 
 | 
         
 | 
        // remove references from object arrays: 
 | 
        if (comparator == objectComparator) { 
 | 
            Object[] objArray = (Object[])array; 
 | 
            for (int i=0; i<objArray.length; i++) { 
 | 
                objArray[i] = null; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
     
 | 
    //////////////////////////////////////////////////////////////////////////// 
 | 
  
 | 
    private static Comparator floatComparator = new ComparatorSerial() { 
 | 
        public int compare(Object o1, Object o2) { 
 | 
            int len1 = (o1 instanceof IntValue)? ((IntValue)o1).value : ((float[])o1).length; 
 | 
            int len2 = (o2 instanceof IntValue)? ((IntValue)o2).value : ((float[])o2).length; 
 | 
            return len1 > len2? 1 : len1 < len2 ? -1 : 0; 
 | 
        } 
 | 
    }; 
 | 
  
 | 
    private static Comparator intComparator = new ComparatorSerial() { 
 | 
        public int compare(Object o1, Object o2) { 
 | 
            int len1 = (o1 instanceof IntValue)? ((IntValue)o1).value : ((int[])o1).length; 
 | 
            int len2 = (o2 instanceof IntValue)? ((IntValue)o2).value : ((int[])o2).length; 
 | 
            return len1 > len2? 1 : len1 < len2 ? -1 : 0; 
 | 
        } 
 | 
    }; 
 | 
     
 | 
    private static Comparator objectComparator = new ComparatorSerial() { 
 | 
        public int compare(Object o1, Object o2) { 
 | 
            int len1 = (o1 instanceof IntValue)? ((IntValue)o1).value : ((Object[])o1).length; 
 | 
            int len2 = (o2 instanceof IntValue)? ((IntValue)o2).value : ((Object[])o2).length; 
 | 
            return len1 > len2? 1 : len1 < len2 ? -1 : 0; 
 | 
        } 
 | 
    }; 
 | 
     
 | 
    public static interface ComparatorSerial<T> extends Comparator<T>, java.io.Serializable 
 | 
        { 
 | 
        } 
 | 
         
 | 
    private static class IntValue  implements java.io.Serializable 
 | 
        { 
 | 
        public int value; 
 | 
    } 
 | 
     
 | 
    //////////////////////////////////////////////////////////////////////////// 
 | 
     
 | 
    private static ThreadLocal<Map> threadLocal = new ThreadLocal<Map>() { 
 | 
        @Override 
 | 
        protected Map initialValue() { 
 | 
            return new HashMap(); 
 | 
        } 
 | 
    }; 
 | 
     
 | 
    /** 
 | 
     * Returns per-thread array pool for given type, or create one if it doesn't exist. 
 | 
     *  
 | 
     * @param cls type 
 | 
     * @return object pool 
 | 
     */ 
 | 
    @SuppressWarnings("unchecked") 
 | 
    public static <T> ArrayPool<T> get(Class cls) { 
 | 
        Map map = threadLocal.get(); 
 | 
         
 | 
        ArrayPool<T> pool = (ArrayPool<T>)map.get(cls); 
 | 
        if (pool == null) { 
 | 
            pool = new ArrayPool<T>(cls); 
 | 
            map.put(cls, pool); 
 | 
        } 
 | 
         
 | 
        return pool; 
 | 
    } 
 | 
  
 | 
    public static void cleanCurrentThread() { 
 | 
        threadLocal.remove(); 
 | 
    } 
 | 
  
 | 
} 
 |