diff --git a/pdb-api/build.gradle b/pdb-api/build.gradle index 6a67192..3afe89b 100644 --- a/pdb-api/build.gradle +++ b/pdb-api/build.gradle @@ -1,4 +1,4 @@ dependencies { - + compile project(':pdb-utils') } \ No newline at end of file diff --git a/pdb-api/src/main/java/org/lucares/pdb/api/Tags.java b/pdb-api/src/main/java/org/lucares/pdb/api/Tags.java index 90b89b9..e783eb6 100644 --- a/pdb-api/src/main/java/org/lucares/pdb/api/Tags.java +++ b/pdb-api/src/main/java/org/lucares/pdb/api/Tags.java @@ -1,28 +1,27 @@ package org.lucares.pdb.api; -import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.function.BiConsumer; +import org.lucares.utils.MiniMap; + public class Tags { public static final Tags EMPTY = new Tags(); - private final Map tags; + private final MiniMap tags; private int cachedHash = 0; private Tags() { super(); - tags = Collections.emptyMap(); + tags = MiniMap.emptyMap(); } - private Tags(final Map tags) { + private Tags(final MiniMap tags) { this.tags = tags; } @@ -31,13 +30,13 @@ public class Tags { } public static Tags create(final String key, final String value) { - final Map tags = new LinkedHashMap<>(1); + final MiniMap tags = new MiniMap<>(); tags.put(key, new Tag(key, value)); return new Tags(tags); } public static Tags create(final String key1, final String value1, final String key2, final String value2) { - final Map tags = new LinkedHashMap<>(2); + final MiniMap tags = new MiniMap<>(); tags.put(key1, new Tag(key1, value1)); tags.put(key2, new Tag(key2, value2)); return new Tags(tags); @@ -45,7 +44,7 @@ public class Tags { public static Tags create(final String key1, final String value1, final String key2, final String value2, final String key3, final String value3) { - final Map tags = new LinkedHashMap<>(3); + final MiniMap tags = new MiniMap<>(); tags.put(key1, new Tag(key1, value1)); tags.put(key2, new Tag(key2, value2)); tags.put(key3, new Tag(key3, value3)); @@ -56,7 +55,7 @@ public class Tags { Objects.requireNonNull(key, "key must not be null"); Objects.requireNonNull(value, "value must not be null"); - final Map newTags = new LinkedHashMap<>(tags); + final MiniMap newTags = new MiniMap<>(tags); newTags.put(key, new Tag(key, value)); @@ -85,8 +84,12 @@ public class Tags { } public void forEach(final BiConsumer keyValueConsumer) { - for (final Map.Entry e : tags.entrySet()) { - keyValueConsumer.accept(e.getKey(), e.getValue().getValue()); + + Set keys = tags.keySet(); + + for (String key : keys) { + final Tag value = tags.get(key); + keyValueConsumer.accept(key, value.getValue()); } } diff --git a/pdb-utils/src/main/java/org/lucares/utils/MiniMap.java b/pdb-utils/src/main/java/org/lucares/utils/MiniMap.java new file mode 100644 index 0000000..ea99955 --- /dev/null +++ b/pdb-utils/src/main/java/org/lucares/utils/MiniMap.java @@ -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 { + + 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 miniMap){ + keys = miniMap.keys.clone(); + values = miniMap.values.clone(); + } + + @SuppressWarnings("unchecked") + public static final MiniMap emptyMap() { + return (MiniMap) 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 map) { + for (java.util.Map.Entry e : map.entrySet()) { + put(e.getKey(), e.getValue()); + } + } + + public void clear() { + keys = EMPTY_ARRAY; + values = EMPTY_ARRAY; + } + + @SuppressWarnings("unchecked") + public Set keySet() { + final Set result = new HashSet<>(keys.length); + + for (Object k : keys) { + result.add((K) k); + } + return result; + } + + @SuppressWarnings("unchecked") + public Set values() { + final Set 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; + } +} diff --git a/pdb-utils/src/test/java/org/lucares/utils/MiniMapTest.java b/pdb-utils/src/test/java/org/lucares/utils/MiniMapTest.java new file mode 100644 index 0000000..1b8b321 --- /dev/null +++ b/pdb-utils/src/test/java/org/lucares/utils/MiniMapTest.java @@ -0,0 +1,26 @@ +package org.lucares.utils; + +import java.util.Map; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test +public class MiniMapTest { + public void testInsertGet() + { + final MiniMap map = new MiniMap<>(); + + String key1 = "key1"; + String key2 = "key2"; + String value1 = "value1"; + String value2 = "value1"; + + + map.put(key1, value1); + map.put(key2, value2); + + Assert.assertEquals(map.get(key1), value1); + Assert.assertEquals(map.get(key2), value2); + } +}