replace LinkedHashMap with a more memory efficient implementation

This saves approximately 50MB of heap space.
This commit is contained in:
2017-09-30 17:50:44 +02:00
parent 7e00594382
commit d4fd25dc4c
4 changed files with 188 additions and 13 deletions

View File

@@ -0,0 +1,146 @@
package org.lucares.utils;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* A memory efficient map implementation. It doesn't implement {@link Map},
* because this class does not support the full API of {@link Map}.
*/
public class MiniMap<K, V> {
private static final Object[] EMPTY_ARRAY = new Object[0];
private static final MiniMap<?,?> EMPTY_MAP = new MiniMap<>();
private Object[] keys;
private Object[] values;
public MiniMap() {
keys = EMPTY_ARRAY;
values = EMPTY_ARRAY;
}
public MiniMap(final MiniMap<K, V> miniMap){
keys = miniMap.keys.clone();
values = miniMap.values.clone();
}
@SuppressWarnings("unchecked")
public static final <K,V> MiniMap<K,V> emptyMap() {
return (MiniMap<K,V>) EMPTY_MAP;
}
public int size() {
return keys.length;
}
public boolean isEmpty() {
return size() == 0;
}
public boolean containsKey(Object key) {
return get(key) != null;
}
@SuppressWarnings("unchecked")
public V get(Object key) {
for (int i = 0; i < keys.length; i++) {
Object object = keys[i];
if (Objects.equals(key, object)) {
return (V) values[i];
}
}
return null;
}
public V put(K key, V value) {
V oldValue = get(key);
if (oldValue != null) {
for (int i = 0; i < keys.length; i++) {
Object object = keys[i];
if (Objects.equals(key, object)) {
values[i] = value;
break;
}
}
} else {
final Object[] newKeys = new Object[keys.length + 1];
System.arraycopy(keys, 0, newKeys, 0, keys.length);
final Object[] newValues = new Object[values.length + 1];
System.arraycopy(values, 0, newValues, 0, values.length);
newKeys[newKeys.length - 1] = key;
newValues[newValues.length - 1] = value;
keys = newKeys;
values = newValues;
}
return oldValue;
}
public void putAll(Map<? extends K, ? extends V> map) {
for (java.util.Map.Entry<? extends K, ? extends V> e : map.entrySet()) {
put(e.getKey(), e.getValue());
}
}
public void clear() {
keys = EMPTY_ARRAY;
values = EMPTY_ARRAY;
}
@SuppressWarnings("unchecked")
public Set<K> keySet() {
final Set<K> result = new HashSet<>(keys.length);
for (Object k : keys) {
result.add((K) k);
}
return result;
}
@SuppressWarnings("unchecked")
public Set<V> values() {
final Set<V> result = new HashSet<>(values.length);
for (Object v : values) {
result.add((V) v);
}
return result;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(keys);
result = prime * result + Arrays.hashCode(values);
return result;
}
@SuppressWarnings("rawtypes")
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MiniMap other = (MiniMap) obj;
if (!Arrays.equals(keys, other.keys))
return false;
if (!Arrays.equals(values, other.values))
return false;
return true;
}
}