• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.animation;
33 
34 import java.lang.reflect.Array;
35 import java.util.HashMap;
36 import java.util.Map;
37 
38 /**
39  * Object is indexed and stored in primitive float[]
40  * @author Lim, YongHoon
41  * @param <T>
42  */
43 public abstract class CompactArray<T> {
44 
45     private Map<T, Integer> indexPool = new HashMap<T, Integer>();
46     protected int[] index;
47     protected float[] array;
48     private boolean invalid;
49 
50     /**
51      * Creates a compact array
52      */
CompactArray()53     public CompactArray() {
54     }
55 
56     /**
57      * create array using serialized data
58      * @param compressedArray
59      * @param index
60      */
CompactArray(float[] compressedArray, int[] index)61     public CompactArray(float[] compressedArray, int[] index) {
62         this.array = compressedArray;
63         this.index = index;
64     }
65 
66     /**
67      * Add objects.
68      * They are serialized automatically when get() method is called.
69      * @param objArray
70      */
add(T... objArray)71     public void add(T... objArray) {
72         if (objArray == null || objArray.length == 0) {
73             return;
74         }
75         invalid = true;
76         int base = 0;
77         if (index == null) {
78             index = new int[objArray.length];
79         } else {
80             if (indexPool.isEmpty()) {
81                 throw new RuntimeException("Internal is already fixed");
82             }
83             base = index.length;
84 
85             int[] tmp = new int[base + objArray.length];
86             System.arraycopy(index, 0, tmp, 0, index.length);
87             index = tmp;
88             //index = Arrays.copyOf(index, base+objArray.length);
89         }
90         for (int j = 0; j < objArray.length; j++) {
91             T obj = objArray[j];
92             if (obj == null) {
93                 index[base + j] = -1;
94             } else {
95                 Integer i = indexPool.get(obj);
96                 if (i == null) {
97                     i = indexPool.size();
98                     indexPool.put(obj, i);
99                 }
100                 index[base + j] = i;
101             }
102         }
103     }
104 
105     /**
106      * release objects.
107      * add() method call is not allowed anymore.
108      */
freeze()109     public void freeze() {
110         serialize();
111         indexPool.clear();
112     }
113 
114     /**
115      * @param index
116      * @param value
117      */
set(int index, T value)118     public final void set(int index, T value) {
119         int j = getCompactIndex(index);
120         serialize(j, value);
121     }
122 
123     /**
124      * returns the object for the given index
125      * @param index the index
126      * @param store an object to store the result
127      * @return
128      */
get(int index, T store)129     public final T get(int index, T store) {
130         serialize();
131         int j = getCompactIndex(index);
132         return deserialize(j, store);
133     }
134 
135     /**
136      * return a float array of serialized data
137      * @return
138      */
getSerializedData()139     public final float[] getSerializedData() {
140         serialize();
141         return array;
142     }
143 
144     /**
145      * serialize this compact array
146      */
serialize()147     public final void serialize() {
148         if (invalid) {
149             int newSize = indexPool.size() * getTupleSize();
150             if (array == null || Array.getLength(array) < newSize) {
151                 array = ensureCapacity(array, newSize);
152                 for (Map.Entry<T, Integer> entry : indexPool.entrySet()) {
153                     int i = entry.getValue();
154                     T obj = entry.getKey();
155                     serialize(i, obj);
156                 }
157             }
158             invalid = false;
159         }
160     }
161 
162     /**
163      * @return compacted array's primitive size
164      */
getSerializedSize()165     protected final int getSerializedSize() {
166         return Array.getLength(getSerializedData());
167     }
168 
169     /**
170      * Ensure the capacity for the given array and the given size
171      * @param arr the array
172      * @param size the size
173      * @return
174      */
ensureCapacity(float[] arr, int size)175     protected float[] ensureCapacity(float[] arr, int size) {
176         if (arr == null) {
177             return new float[size];
178         } else if (arr.length >= size) {
179             return arr;
180         } else {
181             float[] tmp = new float[size];
182             System.arraycopy(arr, 0, tmp, 0, arr.length);
183             return tmp;
184             //return Arrays.copyOf(arr, size);
185         }
186     }
187 
188     /**
189      * retrun an array of indices for the given objects
190      * @param objArray
191      * @return
192      */
getIndex(T... objArray)193     public final int[] getIndex(T... objArray) {
194         int[] index = new int[objArray.length];
195         for (int i = 0; i < index.length; i++) {
196             T obj = objArray[i];
197             index[i] = obj != null ? indexPool.get(obj) : -1;
198         }
199         return index;
200     }
201 
202     /**
203      * returns the corresponding index in the compact array
204      * @param objIndex
205      * @return object index in the compacted object array
206      */
getCompactIndex(int objIndex)207     public int getCompactIndex(int objIndex) {
208         return index != null ? index[objIndex] : objIndex;
209     }
210 
211     /**
212      * @return uncompressed object size
213      */
getTotalObjectSize()214     public final int getTotalObjectSize() {
215         assert getSerializedSize() % getTupleSize() == 0;
216         return index != null ? index.length : getSerializedSize() / getTupleSize();
217     }
218 
219     /**
220      * @return compressed object size
221      */
getCompactObjectSize()222     public final int getCompactObjectSize() {
223         assert getSerializedSize() % getTupleSize() == 0;
224         return getSerializedSize() / getTupleSize();
225     }
226 
227     /**
228      * decompress and return object array
229      * @return decompress and return object array
230      */
toObjectArray()231     public final T[] toObjectArray() {
232         try {
233             T[] compactArr = (T[]) Array.newInstance(getElementClass(), getSerializedSize() / getTupleSize());
234             for (int i = 0; i < compactArr.length; i++) {
235                 compactArr[i] = getElementClass().newInstance();
236                 deserialize(i, compactArr[i]);
237             }
238 
239             T[] objArr = (T[]) Array.newInstance(getElementClass(), getTotalObjectSize());
240             for (int i = 0; i < objArr.length; i++) {
241                 int compactIndex = getCompactIndex(i);
242                 objArr[i] = compactArr[compactIndex];
243             }
244             return objArr;
245         } catch (Exception e) {
246             return null;
247         }
248     }
249 
250     /**
251      * serialize object
252      * @param compactIndex compacted object index
253      * @param store
254      */
serialize(int compactIndex, T store)255     protected abstract void serialize(int compactIndex, T store);
256 
257     /**
258      * deserialize object
259      * @param compactIndex compacted object index
260      * @param store
261      */
deserialize(int compactIndex, T store)262     protected abstract T deserialize(int compactIndex, T store);
263 
264     /**
265      * serialized size of one object element
266      */
getTupleSize()267     protected abstract int getTupleSize();
268 
getElementClass()269     protected abstract Class<T> getElementClass();
270 }
271