aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core/com/jme3/util/ListMap.java
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/core/com/jme3/util/ListMap.java')
-rw-r--r--engine/src/core/com/jme3/util/ListMap.java317
1 files changed, 317 insertions, 0 deletions
diff --git a/engine/src/core/com/jme3/util/ListMap.java b/engine/src/core/com/jme3/util/ListMap.java
new file mode 100644
index 0000000..c5b6de4
--- /dev/null
+++ b/engine/src/core/com/jme3/util/ListMap.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2009-2010 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.util;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Implementation of a Map that favors iteration speed rather than
+ * get/put speed.
+ *
+ * @author Kirill Vainer
+ */
+public final class ListMap<K, V> implements Map<K, V>, Cloneable, Serializable {
+
+ public static void main(String[] args){
+ Map<String, String> map = new ListMap<String, String>();
+ map.put( "bob", "hello");
+ System.out.println(map.get("bob"));
+ map.remove("bob");
+ System.out.println(map.size());
+
+ map.put("abc", "1");
+ map.put("def", "2");
+ map.put("ghi", "3");
+ map.put("jkl", "4");
+ map.put("mno", "5");
+ System.out.println(map.get("ghi"));
+ }
+
+ private final static class ListMapEntry<K, V> implements Map.Entry<K, V>, Cloneable {
+
+ private final K key;
+ private V value;
+
+ public ListMapEntry(K key, V value){
+ this.key = key;
+ this.value = value;
+ }
+
+ public K getKey() {
+ return key;
+ }
+
+ public V getValue() {
+ return value;
+ }
+
+ public V setValue(V v) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ListMapEntry<K, V> clone(){
+ return new ListMapEntry<K, V>(key, value);
+ }
+
+ }
+
+ private final HashMap<K, V> backingMap;
+ private ListMapEntry<K, V>[] entries;
+
+// private final ArrayList<ListMapEntry<K,V>> entries;
+
+ public ListMap(){
+ entries = new ListMapEntry[4];
+ backingMap = new HashMap<K, V>(4);
+// entries = new ArrayList<ListMapEntry<K,V>>();
+ }
+
+ public ListMap(int initialCapacity){
+ entries = new ListMapEntry[initialCapacity];
+ backingMap = new HashMap<K, V>(initialCapacity);
+// entries = new ArrayList<ListMapEntry<K, V>>(initialCapacity);
+ }
+
+ public ListMap(Map<? extends K, ? extends V> map){
+ entries = new ListMapEntry[map.size()];
+ backingMap = new HashMap<K, V>(map.size());
+// entries = new ArrayList<ListMapEntry<K, V>>(map.size());
+ putAll(map);
+ }
+
+ public int size() {
+// return entries.size();
+ return backingMap.size();
+ }
+
+ public Entry<K, V> getEntry(int index){
+// return entries.get(index);
+ return entries[index];
+ }
+
+ public V getValue(int index){
+// return entries.get(index).value;
+ return entries[index].value;
+ }
+
+ public K getKey(int index){
+// return entries.get(index).key;
+ return entries[index].key;
+ }
+
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ private static boolean keyEq(Object keyA, Object keyB){
+ return keyA.hashCode() == keyB.hashCode() ? (keyA == keyB) || keyA.equals(keyB) : false;
+ }
+//
+// private static boolean valEq(Object a, Object b){
+// return a == null ? (b == null) : a.equals(b);
+// }
+
+ public boolean containsKey(Object key) {
+ return backingMap.containsKey( (K) key);
+// if (key == null)
+// throw new IllegalArgumentException();
+//
+// for (int i = 0; i < entries.size(); i++){
+// ListMapEntry<K,V> entry = entries.get(i);
+// if (keyEq(entry.key, key))
+// return true;
+// }
+// return false;
+ }
+
+ public boolean containsValue(Object value) {
+ return backingMap.containsValue( (V) value);
+// for (int i = 0; i < entries.size(); i++){
+// if (valEq(entries.get(i).value, value))
+// return true;
+// }
+// return false;
+ }
+
+ public V get(Object key) {
+ return backingMap.get( (K) key);
+// if (key == null)
+// throw new IllegalArgumentException();
+//
+// for (int i = 0; i < entries.size(); i++){
+// ListMapEntry<K,V> entry = entries.get(i);
+// if (keyEq(entry.key, key))
+// return entry.value;
+// }
+// return null;
+ }
+
+ public V put(K key, V value) {
+ if (backingMap.containsKey(key)){
+ // set the value on the entry
+ int size = size();
+ for (int i = 0; i < size; i++){
+ ListMapEntry<K, V> entry = entries[i];
+ if (keyEq(entry.key, key)){
+ entry.value = value;
+ break;
+ }
+ }
+ }else{
+ int size = size();
+ // expand list as necessary
+ if (size == entries.length){
+ ListMapEntry<K, V>[] tmpEntries = entries;
+ entries = new ListMapEntry[size * 2];
+ System.arraycopy(tmpEntries, 0, entries, 0, size);
+ }
+ entries[size] = new ListMapEntry<K, V>(key, value);
+ }
+ return backingMap.put(key, value);
+// if (key == null)
+// throw new IllegalArgumentException();
+//
+// // check if entry exists, if yes, overwrite it with new value
+// for (int i = 0; i < entries.size(); i++){
+// ListMapEntry<K,V> entry = entries.get(i);
+// if (keyEq(entry.key, key)){
+// V prevValue = entry.value;
+// entry.value = value;
+// return prevValue;
+// }
+// }
+//
+// // add a new entry
+// entries.add(new ListMapEntry<K, V>(key, value));
+// return null;
+ }
+
+ public V remove(Object key) {
+ V element = backingMap.remove( (K) key);
+ if (element != null){
+ // find removed element
+ int size = size() + 1; // includes removed element
+ int removedIndex = -1;
+ for (int i = 0; i < size; i++){
+ ListMapEntry<K, V> entry = entries[i];
+ if (keyEq(entry.key, key)){
+ removedIndex = i;
+ break;
+ }
+ }
+ assert removedIndex >= 0;
+
+ size --;
+ for (int i = removedIndex; i < size; i++){
+ entries[i] = entries[i+1];
+ }
+ }
+ return element;
+// if (key == null)
+// throw new IllegalArgumentException();
+//
+// for (int i = 0; i < entries.size(); i++){
+// ListMapEntry<K,V> entry = entries.get(i);
+// if (keyEq(entry.key, key)){
+// return entries.remove(i).value;
+// }
+// }
+// return null;
+ }
+
+ public void putAll(Map<? extends K, ? extends V> map) {
+ for (Entry<? extends K, ? extends V> entry : map.entrySet()){
+ put(entry.getKey(), entry.getValue());
+ }
+
+
+// if (map instanceof ListMap){
+// ListMap<K, V> listMap = (ListMap<K, V>) map;
+// ArrayList<ListMapEntry<K, V>> otherEntries = listMap.entries;
+// for (int i = 0; i < otherEntries.size(); i++){
+// ListMapEntry<K, V> entry = otherEntries.get(i);
+// put(entry.key, entry.value);
+// }
+// }else{
+// for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()){
+// put(entry.getKey(), entry.getValue());
+// }
+// }
+ }
+
+ public void clear() {
+ backingMap.clear();
+// entries.clear();
+ }
+
+ @Override
+ public ListMap<K, V> clone(){
+ ListMap<K, V> clone = new ListMap<K, V>(size());
+ clone.putAll(this);
+ return clone;
+ }
+
+ public Set<K> keySet() {
+ return backingMap.keySet();
+// HashSet<K> keys = new HashSet<K>();
+// for (int i = 0; i < entries.size(); i++){
+// ListMapEntry<K,V> entry = entries.get(i);
+// keys.add(entry.key);
+// }
+// return keys;
+ }
+
+ public Collection<V> values() {
+ return backingMap.values();
+// ArrayList<V> values = new ArrayList<V>();
+// for (int i = 0; i < entries.size(); i++){
+// ListMapEntry<K,V> entry = entries.get(i);
+// values.add(entry.value);
+// }
+// return values;
+ }
+
+ public Set<Entry<K, V>> entrySet() {
+ return backingMap.entrySet();
+// HashSet<Entry<K, V>> entryset = new HashSet<Entry<K, V>>();
+// entryset.addAll(entries);
+// return entryset;
+ }
+
+}