/* * Copyright (c) 2009-2012 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'jMonkeyEngine' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.jme3.animation; import java.lang.reflect.Array; import java.util.HashMap; import java.util.Map; /** * Object is indexed and stored in primitive float[] * @author Lim, YongHoon * @param <T> */ public abstract class CompactArray<T> { private Map<T, Integer> indexPool = new HashMap<T, Integer>(); protected int[] index; protected float[] array; private boolean invalid; /** * Creates a compact array */ public CompactArray() { } /** * create array using serialized data * @param compressedArray * @param index */ public CompactArray(float[] compressedArray, int[] index) { this.array = compressedArray; this.index = index; } /** * Add objects. * They are serialized automatically when get() method is called. * @param objArray */ public void add(T... objArray) { if (objArray == null || objArray.length == 0) { return; } invalid = true; int base = 0; if (index == null) { index = new int[objArray.length]; } else { if (indexPool.isEmpty()) { throw new RuntimeException("Internal is already fixed"); } base = index.length; int[] tmp = new int[base + objArray.length]; System.arraycopy(index, 0, tmp, 0, index.length); index = tmp; //index = Arrays.copyOf(index, base+objArray.length); } for (int j = 0; j < objArray.length; j++) { T obj = objArray[j]; if (obj == null) { index[base + j] = -1; } else { Integer i = indexPool.get(obj); if (i == null) { i = indexPool.size(); indexPool.put(obj, i); } index[base + j] = i; } } } /** * release objects. * add() method call is not allowed anymore. */ public void freeze() { serialize(); indexPool.clear(); } /** * @param index * @param value */ public final void set(int index, T value) { int j = getCompactIndex(index); serialize(j, value); } /** * returns the object for the given index * @param index the index * @param store an object to store the result * @return */ public final T get(int index, T store) { serialize(); int j = getCompactIndex(index); return deserialize(j, store); } /** * return a float array of serialized data * @return */ public final float[] getSerializedData() { serialize(); return array; } /** * serialize this compact array */ public final void serialize() { if (invalid) { int newSize = indexPool.size() * getTupleSize(); if (array == null || Array.getLength(array) < newSize) { array = ensureCapacity(array, newSize); for (Map.Entry<T, Integer> entry : indexPool.entrySet()) { int i = entry.getValue(); T obj = entry.getKey(); serialize(i, obj); } } invalid = false; } } /** * @return compacted array's primitive size */ protected final int getSerializedSize() { return Array.getLength(getSerializedData()); } /** * Ensure the capacity for the given array and the given size * @param arr the array * @param size the size * @return */ protected float[] ensureCapacity(float[] arr, int size) { if (arr == null) { return new float[size]; } else if (arr.length >= size) { return arr; } else { float[] tmp = new float[size]; System.arraycopy(arr, 0, tmp, 0, arr.length); return tmp; //return Arrays.copyOf(arr, size); } } /** * retrun an array of indices for the given objects * @param objArray * @return */ public final int[] getIndex(T... objArray) { int[] index = new int[objArray.length]; for (int i = 0; i < index.length; i++) { T obj = objArray[i]; index[i] = obj != null ? indexPool.get(obj) : -1; } return index; } /** * returns the corresponding index in the compact array * @param objIndex * @return object index in the compacted object array */ public int getCompactIndex(int objIndex) { return index != null ? index[objIndex] : objIndex; } /** * @return uncompressed object size */ public final int getTotalObjectSize() { assert getSerializedSize() % getTupleSize() == 0; return index != null ? index.length : getSerializedSize() / getTupleSize(); } /** * @return compressed object size */ public final int getCompactObjectSize() { assert getSerializedSize() % getTupleSize() == 0; return getSerializedSize() / getTupleSize(); } /** * decompress and return object array * @return decompress and return object array */ public final T[] toObjectArray() { try { T[] compactArr = (T[]) Array.newInstance(getElementClass(), getSerializedSize() / getTupleSize()); for (int i = 0; i < compactArr.length; i++) { compactArr[i] = getElementClass().newInstance(); deserialize(i, compactArr[i]); } T[] objArr = (T[]) Array.newInstance(getElementClass(), getTotalObjectSize()); for (int i = 0; i < objArr.length; i++) { int compactIndex = getCompactIndex(i); objArr[i] = compactArr[compactIndex]; } return objArr; } catch (Exception e) { return null; } } /** * serialize object * @param compactIndex compacted object index * @param store */ protected abstract void serialize(int compactIndex, T store); /** * deserialize object * @param compactIndex compacted object index * @param store */ protected abstract T deserialize(int compactIndex, T store); /** * serialized size of one object element */ protected abstract int getTupleSize(); protected abstract Class<T> getElementClass(); }