• 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 
33 package com.jme3.util;
34 
35 import java.io.Serializable;
36 import java.util.Collection;
37 import java.util.HashMap;
38 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.Set;
41 
42 /**
43  * Implementation of a Map that favors iteration speed rather than
44  * get/put speed.
45  *
46  * @author Kirill Vainer
47  */
48 public final class ListMap<K, V> implements Map<K, V>, Cloneable, Serializable {
49 
main(String[] args)50     public static void main(String[] args){
51         Map<String, String> map = new ListMap<String, String>();
52         map.put( "bob", "hello");
53         System.out.println(map.get("bob"));
54         map.remove("bob");
55         System.out.println(map.size());
56 
57         map.put("abc", "1");
58         map.put("def", "2");
59         map.put("ghi", "3");
60         map.put("jkl", "4");
61         map.put("mno", "5");
62         System.out.println(map.get("ghi"));
63     }
64 
65     private final static class ListMapEntry<K, V> implements Map.Entry<K, V>, Cloneable {
66 
67         private final K key;
68         private V value;
69 
ListMapEntry(K key, V value)70         public ListMapEntry(K key, V value){
71             this.key = key;
72             this.value = value;
73         }
74 
getKey()75         public K getKey() {
76             return key;
77         }
78 
getValue()79         public V getValue() {
80             return value;
81         }
82 
setValue(V v)83         public V setValue(V v) {
84             throw new UnsupportedOperationException();
85         }
86 
87         @Override
clone()88         public ListMapEntry<K, V> clone(){
89             return new ListMapEntry<K, V>(key, value);
90         }
91 
92     }
93 
94     private final HashMap<K, V> backingMap;
95     private ListMapEntry<K, V>[] entries;
96 
97 //    private final ArrayList<ListMapEntry<K,V>> entries;
98 
ListMap()99     public ListMap(){
100         entries = new ListMapEntry[4];
101         backingMap = new HashMap<K, V>(4);
102 //       entries = new ArrayList<ListMapEntry<K,V>>();
103     }
104 
ListMap(int initialCapacity)105     public ListMap(int initialCapacity){
106         entries = new ListMapEntry[initialCapacity];
107         backingMap = new HashMap<K, V>(initialCapacity);
108 //        entries = new ArrayList<ListMapEntry<K, V>>(initialCapacity);
109     }
110 
ListMap(Map<? extends K, ? extends V> map)111     public ListMap(Map<? extends K, ? extends V> map){
112         entries = new ListMapEntry[map.size()];
113         backingMap = new HashMap<K, V>(map.size());
114 //        entries = new ArrayList<ListMapEntry<K, V>>(map.size());
115         putAll(map);
116     }
117 
size()118     public int size() {
119 //        return entries.size();
120         return backingMap.size();
121     }
122 
getEntry(int index)123     public Entry<K, V> getEntry(int index){
124 //        return entries.get(index);
125         return entries[index];
126     }
127 
getValue(int index)128     public V getValue(int index){
129 //        return entries.get(index).value;
130         return entries[index].value;
131     }
132 
getKey(int index)133     public K getKey(int index){
134 //        return entries.get(index).key;
135         return entries[index].key;
136     }
137 
isEmpty()138     public boolean isEmpty() {
139         return size() == 0;
140     }
141 
keyEq(Object keyA, Object keyB)142     private static boolean keyEq(Object keyA, Object keyB){
143         return keyA.hashCode() == keyB.hashCode() ? (keyA == keyB) || keyA.equals(keyB) : false;
144     }
145 //
146 //    private static boolean valEq(Object a, Object b){
147 //        return a == null ? (b == null) : a.equals(b);
148 //    }
149 
containsKey(Object key)150     public boolean containsKey(Object key) {
151         return backingMap.containsKey( (K) key);
152 //        if (key == null)
153 //            throw new IllegalArgumentException();
154 //
155 //        for (int i = 0; i < entries.size(); i++){
156 //            ListMapEntry<K,V> entry = entries.get(i);
157 //            if (keyEq(entry.key, key))
158 //                return true;
159 //        }
160 //        return false;
161     }
162 
containsValue(Object value)163     public boolean containsValue(Object value) {
164         return backingMap.containsValue( (V) value);
165 //        for (int i = 0; i < entries.size(); i++){
166 //            if (valEq(entries.get(i).value, value))
167 //                return true;
168 //        }
169 //        return false;
170     }
171 
get(Object key)172     public V get(Object key) {
173         return backingMap.get( (K) key);
174 //        if (key == null)
175 //            throw new IllegalArgumentException();
176 //
177 //        for (int i = 0; i < entries.size(); i++){
178 //            ListMapEntry<K,V> entry = entries.get(i);
179 //            if (keyEq(entry.key, key))
180 //                return entry.value;
181 //        }
182 //        return null;
183     }
184 
put(K key, V value)185     public V put(K key, V value) {
186         if (backingMap.containsKey(key)){
187             // set the value on the entry
188             int size = size();
189             for (int i = 0; i < size; i++){
190                 ListMapEntry<K, V> entry = entries[i];
191                 if (keyEq(entry.key, key)){
192                     entry.value = value;
193                     break;
194                 }
195             }
196         }else{
197             int size = size();
198             // expand list as necessary
199             if (size == entries.length){
200                 ListMapEntry<K, V>[] tmpEntries = entries;
201                 entries = new ListMapEntry[size * 2];
202                 System.arraycopy(tmpEntries, 0, entries, 0, size);
203             }
204             entries[size] = new ListMapEntry<K, V>(key, value);
205         }
206         return backingMap.put(key, value);
207 //        if (key == null)
208 //            throw new IllegalArgumentException();
209 //
210 //        // check if entry exists, if yes, overwrite it with new value
211 //        for (int i = 0; i < entries.size(); i++){
212 //            ListMapEntry<K,V> entry = entries.get(i);
213 //            if (keyEq(entry.key, key)){
214 //                V prevValue = entry.value;
215 //                entry.value = value;
216 //                return prevValue;
217 //            }
218 //        }
219 //
220 //        // add a new entry
221 //        entries.add(new ListMapEntry<K, V>(key, value));
222 //        return null;
223     }
224 
remove(Object key)225     public V remove(Object key) {
226         V element = backingMap.remove( (K) key);
227         if (element != null){
228             // find removed element
229             int size = size() + 1; // includes removed element
230             int removedIndex = -1;
231             for (int i = 0; i < size; i++){
232                 ListMapEntry<K, V> entry = entries[i];
233                 if (keyEq(entry.key, key)){
234                     removedIndex = i;
235                     break;
236                 }
237             }
238             assert removedIndex >= 0;
239 
240             size --;
241             for (int i = removedIndex; i < size; i++){
242                 entries[i] = entries[i+1];
243             }
244         }
245         return element;
246 //        if (key == null)
247 //            throw new IllegalArgumentException();
248 //
249 //        for (int i = 0; i < entries.size(); i++){
250 //            ListMapEntry<K,V> entry = entries.get(i);
251 //            if (keyEq(entry.key, key)){
252 //                return entries.remove(i).value;
253 //            }
254 //        }
255 //        return null;
256     }
257 
putAll(Map<? extends K, ? extends V> map)258     public void putAll(Map<? extends K, ? extends V> map) {
259         for (Entry<? extends K, ? extends V> entry : map.entrySet()){
260             put(entry.getKey(), entry.getValue());
261         }
262 
263 
264 //        if (map instanceof ListMap){
265 //            ListMap<K, V> listMap = (ListMap<K, V>) map;
266 //            ArrayList<ListMapEntry<K, V>> otherEntries = listMap.entries;
267 //            for (int i = 0; i < otherEntries.size(); i++){
268 //                ListMapEntry<K, V> entry = otherEntries.get(i);
269 //                put(entry.key, entry.value);
270 //            }
271 //        }else{
272 //            for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()){
273 //                put(entry.getKey(), entry.getValue());
274 //            }
275 //        }
276     }
277 
clear()278     public void clear() {
279         backingMap.clear();
280 //        entries.clear();
281     }
282 
283     @Override
clone()284     public ListMap<K, V> clone(){
285         ListMap<K, V> clone = new ListMap<K, V>(size());
286         clone.putAll(this);
287         return clone;
288     }
289 
keySet()290     public Set<K> keySet() {
291         return backingMap.keySet();
292 //        HashSet<K> keys = new HashSet<K>();
293 //        for (int i = 0; i < entries.size(); i++){
294 //            ListMapEntry<K,V> entry = entries.get(i);
295 //            keys.add(entry.key);
296 //        }
297 //        return keys;
298     }
299 
values()300     public Collection<V> values() {
301         return backingMap.values();
302 //        ArrayList<V> values = new ArrayList<V>();
303 //        for (int i = 0; i < entries.size(); i++){
304 //            ListMapEntry<K,V> entry = entries.get(i);
305 //            values.add(entry.value);
306 //        }
307 //        return values;
308     }
309 
entrySet()310     public Set<Entry<K, V>> entrySet() {
311         return backingMap.entrySet();
312 //        HashSet<Entry<K, V>> entryset = new HashSet<Entry<K, V>>();
313 //        entryset.addAll(entries);
314 //        return entryset;
315     }
316 
317 }
318