Skip to content

Commit 4d2cc4d

Browse files
committed
Split class hierarchy, so common case of "not using defaults" saves a bit of memory on CompactHashMapClassEmptyDefaults instance fields
1 parent 8c363b4 commit 4d2cc4d

File tree

5 files changed

+68
-42
lines changed

5 files changed

+68
-42
lines changed

core/src/main/java/vlsi/utils/CompactHashMapClass.java

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,26 @@
2626
import java.io.ObjectOutputStream;
2727
import java.util.*;
2828

29-
public class CompactHashMapClass<K, V> {
29+
abstract class CompactHashMapClass<K, V> {
3030
public static final CompactHashMapClass EMPTY = new CompactHashMapClassEmptyDefaults(
3131
new com.github.andrewoma.dexx.collection.HashMap());
3232

3333
final com.github.andrewoma.dexx.collection.Map<K, Integer> key2slot; // Immutable
34-
final Map<K, V> defaultValues; // Immutable
35-
36-
// Reference to the map with defaultValues == emptyMap
37-
private CompactHashMapClassEmptyDefaults<K, V> mapWithEmptyDefaults;
3834

3935
// This value is used as a marker of deleted object
4036
// "new String" is required to avoid clashing with regular strings
4137
public static final String REMOVED_OBJECT = new String("Non existing mapping value");
4238

43-
public CompactHashMapClass(com.github.andrewoma.dexx.collection.Map<K, Integer> key2slot, Map<K, V> defaultValues, CompactHashMapClassEmptyDefaults<K, V> mapWithEmptyDefaults) {
39+
public CompactHashMapClass(com.github.andrewoma.dexx.collection.Map<K, Integer> key2slot) {
4440
this.key2slot = key2slot;
45-
this.defaultValues = defaultValues;
46-
this.mapWithEmptyDefaults = mapWithEmptyDefaults;
4741
}
4842

49-
public CompactHashMapClass(com.github.andrewoma.dexx.collection.Map<K, Integer> key2slot) {
50-
this.key2slot = key2slot;
51-
this.defaultValues = Collections.emptyMap();
52-
this.mapWithEmptyDefaults = (CompactHashMapClassEmptyDefaults<K, V>) this;
43+
protected Map<K, V> getDefaultValues() {
44+
return Collections.emptyMap();
5345
}
5446

47+
protected abstract CompactHashMapClassEmptyDefaults<K, V> getMapWithEmptyDefaults();
48+
5549
public V get(CompactHashMap<K, V> map, K key) {
5650
Object result = getInternal(map, key);
5751
return result != REMOVED_OBJECT ? (V) result : null;
@@ -60,7 +54,7 @@ public V get(CompactHashMap<K, V> map, K key) {
6054
private Object getInternal(CompactHashMap<K, V> map, Object key) {
6155
final Integer slot = key2slot.get((K) key);
6256
if (slot == null)
63-
return defaultValues.get(key);
57+
return getDefaultValues().get(key);
6458

6559
return getValueFromSlot(map, slot);
6660
}
@@ -82,12 +76,12 @@ public V put(CompactHashMap<K, V> map, K key, Object value) {
8276
Integer slot = key2slot.get(key);
8377
Object prevValue = REMOVED_OBJECT;
8478
if (slot == null) {
85-
prevValue = defaultValues.get(key);
79+
prevValue = getDefaultValues().get(key);
8680

8781
// Try put value as "default"
88-
Map<K, V> newDef = CompactHashMapDefaultValues.getNewDefaultValues(defaultValues, key, value);
82+
Map<K, V> newDef = CompactHashMapDefaultValues.getNewDefaultValues(getDefaultValues(), key, value);
8983
if (newDef != null) {
90-
map.klass = mapWithEmptyDefaults.getNewDefaultClass(newDef);
84+
map.klass = getMapWithEmptyDefaults().getNewDefaultClass(newDef);
9185
return (V) prevValue;
9286
}
9387

@@ -125,7 +119,7 @@ public V put(CompactHashMap<K, V> map, K key, Object value) {
125119
}
126120

127121
private Integer createNewSlot(CompactHashMap<K, V> map, K key) {
128-
final CompactHashMapClass<K, V> nextKlass = mapWithEmptyDefaults.getNextKlass(key, defaultValues);
122+
final CompactHashMapClass<K, V> nextKlass = getMapWithEmptyDefaults().getNextKlass(key, getDefaultValues());
129123
map.klass = nextKlass;
130124

131125
int prevSize = key2slot.size();
@@ -151,7 +145,7 @@ private Integer createNewSlot(CompactHashMap<K, V> map, K key) {
151145
}
152146

153147
public int size(CompactHashMap<K, V> map) {
154-
return key2slot.size() + defaultValues.size() - removedSlotsCount(map);
148+
return key2slot.size() + getDefaultValues().size() - removedSlotsCount(map);
155149
}
156150

157151
private int removedSlotsCount(CompactHashMap<K, V> map) {
@@ -181,7 +175,7 @@ public boolean containsKey(CompactHashMap<K, V> map, Object key) {
181175
// existing, but null default value
182176
final Integer slot = key2slot.get((K) key);
183177
if (slot == null)
184-
return defaultValues.containsKey(key);
178+
return getDefaultValues().containsKey(key);
185179

186180
return getValueFromSlot(map, slot) != REMOVED_OBJECT;
187181
}
@@ -213,7 +207,7 @@ public void serialize(final CompactHashMap<K, V> map, final ObjectOutputStream s
213207
}
214208

215209
// Serialize default values as separate map
216-
s.writeObject(defaultValues);
210+
s.writeObject(getDefaultValues());
217211
}
218212

219213
public static <K, V> void deserialize(CompactHashMap<K, V> map, ObjectInputStream s) throws IOException, ClassNotFoundException {
@@ -341,7 +335,7 @@ static abstract class HashIterator<K, V, E> implements Iterator<E> {
341335
public HashIterator(CompactHashMap<K, V> map) {
342336
this.map = map;
343337
if (map.isEmpty()) return;
344-
this.it = map.klass.defaultValues.entrySet().iterator();
338+
this.it = map.klass.getDefaultValues().entrySet().iterator();
345339
advance();
346340
}
347341

core/src/main/java/vlsi/utils/CompactHashMapClassEmptyDefaults.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,17 @@
3434
* @param <K> the type of keys maintained by this map
3535
* @param <V> the type of mapped values
3636
*/
37-
public class CompactHashMapClassEmptyDefaults<K, V> extends CompactHashMapClass<K, V> {
38-
Map<K, CompactHashMapClassEmptyDefaults<K, V>> key2newKlass;
39-
Map<Map<K, V>, CompactHashMapClass<K, V>> defValues2Klass;
37+
class CompactHashMapClassEmptyDefaults<K, V> extends CompactHashMapClass<K, V> {
38+
private Map<K, CompactHashMapClassEmptyDefaults<K, V>> key2newKlass;
39+
private Map<Map<K, V>, CompactHashMapClass<K, V>> defValues2Klass;
4040

41-
public CompactHashMapClassEmptyDefaults(com.github.andrewoma.dexx.collection.Map<K, Integer> newKey2slot) {
42-
super(newKey2slot);
41+
public CompactHashMapClassEmptyDefaults(com.github.andrewoma.dexx.collection.Map<K, Integer> key2Slot) {
42+
super(key2Slot);
43+
}
44+
45+
@Override
46+
protected CompactHashMapClassEmptyDefaults<K, V> getMapWithEmptyDefaults() {
47+
return this;
4348
}
4449

4550
protected CompactHashMapClass<K, V> getNewDefaultClass(Map<K, V> newDef) {
@@ -54,7 +59,7 @@ protected CompactHashMapClass<K, V> getNewDefaultClass(Map<K, V> newDef) {
5459

5560
newClass = defValues2Klass.get(newDef);
5661
if (newClass == null) {
57-
newClass = new CompactHashMapClass<K, V>(key2slot, newDef, this);
62+
newClass = new CompactHashMapClassWithDefaults<K, V>(key2slot, newDef, this);
5863
defValues2Klass.put(newDef, newClass);
5964
}
6065
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package vlsi.utils;
2+
3+
import java.util.Map;
4+
5+
class CompactHashMapClassWithDefaults<K, V> extends CompactHashMapClass<K, V> {
6+
private final Map<K, V> defaultValues;
7+
private final CompactHashMapClassEmptyDefaults<K, V> mapClassEmptyDefaults;
8+
9+
public CompactHashMapClassWithDefaults(
10+
com.github.andrewoma.dexx.collection.Map<K, Integer> key2Slot,
11+
Map<K, V> defaultValues,
12+
CompactHashMapClassEmptyDefaults<K, V> mapClassEmptyDefaults) {
13+
super(key2Slot);
14+
this.defaultValues = defaultValues;
15+
this.mapClassEmptyDefaults = mapClassEmptyDefaults;
16+
}
17+
18+
@Override
19+
protected Map<K, V> getDefaultValues() {
20+
return defaultValues;
21+
}
22+
23+
@Override
24+
protected CompactHashMapClassEmptyDefaults<K, V> getMapWithEmptyDefaults() {
25+
return mapClassEmptyDefaults;
26+
}
27+
}

core/src/main/java/vlsi/utils/CompactHashMapDefaultValues.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class CompactHashMapDefaultValues {
3535
private static Lock readLock = readWriteLock.readLock();
3636
private static Lock writeLock = readWriteLock.writeLock();
3737

38-
public static final String[] ALL_VALUES_MATCH = new String[]{"All values match"};
38+
public static final String ALL_VALUES_MATCH = new String("All values match");
3939

4040
public static void clear() {
4141
writeLock.lock();

core/src/test/java/vlsi/utils/CompactHashMapClassTest.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void nonDefaultIsStored() {
4444
Assert.assertEquals(map.put("test", "abc"), null);
4545
Assert.assertEquals(map.get("test"), "abc");
4646
Assert.assertEquals(map.size(), 1);
47-
Assert.assertEquals(map.klass.defaultValues.size(), 0);
47+
Assert.assertEquals(map.klass.getDefaultValues().size(), 0);
4848
}
4949

5050
@Test
@@ -53,7 +53,7 @@ public void putPutGet20() {
5353
for (int i = 0; i < 20; i++) {
5454
Assert.assertEquals(map.put("k" + i, "v" + i), null);
5555
Assert.assertEquals(map.size(), i + 1);
56-
Assert.assertEquals(map.klass.defaultValues.size(), 0);
56+
Assert.assertEquals(map.klass.getDefaultValues().size(), 0);
5757
for (int j = 0; j < i; j++) {
5858
Assert.assertEquals(map.get("k" + j), "v" + j);
5959
}
@@ -68,14 +68,14 @@ public void putPutGet20WithDefault() {
6868
for (int i = 0; i < SIZE; i++) {
6969
Assert.assertEquals(map.put("k" + i, "v" + i), null);
7070
Assert.assertEquals(map.size(), i + 1);
71-
Assert.assertEquals(map.klass.defaultValues.size(), i >= 1 ? 1 : 0);
71+
Assert.assertEquals(map.klass.getDefaultValues().size(), i >= 1 ? 1 : 0);
7272
for (int j = 0; j < i; j++) {
7373
Assert.assertEquals(map.get("k" + j), "v" + j);
7474
}
7575
}
7676
Assert.assertEquals(map.remove("k1"), "v1");
7777
Assert.assertEquals(map.size(), SIZE - 1);
78-
Assert.assertEquals(map.klass.defaultValues.size(), 0);
78+
Assert.assertEquals(map.klass.getDefaultValues().size(), 0);
7979
}
8080

8181
@Test
@@ -86,17 +86,17 @@ public void putDefault() {
8686
Assert.assertEquals(map.put("default", "a"), null);
8787
Assert.assertEquals(map.get("default"), "a");
8888
Assert.assertEquals(map.size(), 1);
89-
Assert.assertEquals(map.klass.defaultValues.size(), 1);
89+
Assert.assertEquals(map.klass.getDefaultValues().size(), 1);
9090

9191
Assert.assertEquals(map.put("default", "b"), "a");
9292
Assert.assertEquals(map.get("default"), "b");
9393
Assert.assertEquals(map.size(), 1);
94-
Assert.assertEquals(map.klass.defaultValues.size(), 1);
94+
Assert.assertEquals(map.klass.getDefaultValues().size(), 1);
9595

9696
Assert.assertEquals(map.putOrRemove("default", CompactHashMapClass.REMOVED_OBJECT), "b");
9797
Assert.assertEquals(map.get("default"), null);
9898
Assert.assertEquals(map.size(), 0);
99-
Assert.assertEquals(map.klass.defaultValues.size(), 0);
99+
Assert.assertEquals(map.klass.getDefaultValues().size(), 0);
100100
}
101101

102102
@Test
@@ -106,22 +106,22 @@ public void putDefaultSpecificValue() {
106106
Assert.assertEquals(map.put("test", "testDefaultValue"), null);
107107
Assert.assertEquals(map.get("test"), "testDefaultValue");
108108
Assert.assertEquals(map.size(), 1);
109-
Assert.assertEquals(map.klass.defaultValues.size(), 1);
109+
Assert.assertEquals(map.klass.getDefaultValues().size(), 1);
110110

111111
Assert.assertEquals(map.put("test", "non-default"), "testDefaultValue");
112112
Assert.assertEquals(map.get("test"), "non-default");
113113
Assert.assertEquals(map.size(), 1);
114-
Assert.assertEquals(map.klass.defaultValues.size(), 0);
114+
Assert.assertEquals(map.klass.getDefaultValues().size(), 0);
115115

116116
Assert.assertEquals(map.put("test", "testDefaultValue"), "non-default");
117117
Assert.assertEquals(map.get("test"), "testDefaultValue");
118118
Assert.assertEquals(map.size(), 1);
119-
Assert.assertEquals(map.klass.defaultValues.size(), 0);
119+
Assert.assertEquals(map.klass.getDefaultValues().size(), 0);
120120

121121
Assert.assertEquals(map.putOrRemove("test", CompactHashMapClass.REMOVED_OBJECT), "testDefaultValue");
122122
Assert.assertEquals(map.get("test"), null);
123123
Assert.assertTrue(map.size() == 0 || map.size() == 1); // we allow to count deleted objects in size
124-
Assert.assertEquals(map.klass.defaultValues.size(), 0);
124+
Assert.assertEquals(map.klass.getDefaultValues().size(), 0);
125125
}
126126

127127
@Test
@@ -133,19 +133,19 @@ public void putDefaultAndRegular() {
133133
Assert.assertEquals(map.get("default"), "x");
134134
Assert.assertEquals(map.get("qwer"), null);
135135
Assert.assertEquals(map.size(), 1);
136-
Assert.assertEquals(map.klass.defaultValues.size(), 1);
136+
Assert.assertEquals(map.klass.getDefaultValues().size(), 1);
137137

138138
Assert.assertEquals(map.put("qwer", "b"), null);
139139
Assert.assertEquals(map.get("default"), "x");
140140
Assert.assertEquals(map.get("qwer"), "b");
141141
Assert.assertEquals(map.size(), 2);
142-
Assert.assertEquals(map.klass.defaultValues.size(), 1);
142+
Assert.assertEquals(map.klass.getDefaultValues().size(), 1);
143143

144144
Assert.assertEquals(map.put("default", "y"), "x");
145145
Assert.assertEquals(map.get("default"), "y");
146146
Assert.assertEquals(map.get("qwer"), "b");
147147
Assert.assertEquals(map.size(), 2);
148-
Assert.assertEquals(map.klass.defaultValues.size(), 1);
148+
Assert.assertEquals(map.klass.getDefaultValues().size(), 1);
149149
}
150150

151151
@Test

0 commit comments

Comments
 (0)