Skip to content

Commit 8d879ed

Browse files
committed
Poke at it a bit more
1 parent 9d406c2 commit 8d879ed

File tree

2 files changed

+130
-46
lines changed

2 files changed

+130
-46
lines changed

tools/cldr-code/src/main/java/org/unicode/cldr/util/NestedMap.java

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.unicode.cldr.util;
22

33
import com.google.common.collect.ImmutableMap;
4+
import com.google.common.collect.MapDifference;
5+
import com.google.common.collect.Maps;
46
import java.util.ArrayDeque;
57
import java.util.ArrayList;
68
import java.util.Deque;
@@ -22,7 +24,7 @@
2224
* ENGINE CLASS A generic, nested map structure that can handle a variable number of levels. This
2325
* class provides the core logic and is wrapped by the type-safe shims.
2426
*
25-
* <p>Various nested Multimaps can be created by using an extra layer with Boolean. Multimap2<K1,
27+
* <p>Various nested Multisets can be created by using an extra layer with Boolean. Multimap2<K1,
2628
* K2, V> == NestedMap3<K1, K2, V, Boolean>
2729
*/
2830
public class NestedMap {
@@ -97,6 +99,20 @@ public String toString() {
9799
return root.toString();
98100
}
99101

102+
@Override
103+
public boolean equals(Object obj) {
104+
return root.equals(((NestedMap) obj).root);
105+
}
106+
107+
@Override
108+
public int hashCode() {
109+
return root.hashCode();
110+
}
111+
112+
public MapDifference<Object, Object> difference(NestedMap other) {
113+
return Maps.difference(root, other.root);
114+
}
115+
100116
// --- IMMUTABILITY ---
101117

102118
/**
@@ -198,36 +214,43 @@ public boolean tryAdvance(Consumer<? super List<Object>> action) {
198214
}
199215
}
200216

217+
@SuppressWarnings("unchecked")
201218
public static class NestedMap2<K1, K2, V> {
202219
private final NestedMap engine;
203220

204221
private NestedMap2(NestedMap engine) {
205222
this.engine = engine;
206223
}
207224

208-
public static <K1 extends Comparable<K1>, K2 extends Comparable<K2>, V>
209-
NestedMap2<K1, K2, V> createWithTreeMaps() {
210-
return new NestedMap2<>(new NestedMap(TreeMap::new));
225+
/** Takes Treemap::new, HashMap::new, ConcurrentHashMap::new, and other suppliers */
226+
public static <K1, K2, V> NestedMap2<K1, K2, V> create(
227+
Supplier<Map<Object, Object>> supplier) {
228+
return new NestedMap2<>(new NestedMap(supplier));
229+
}
230+
231+
@Override
232+
public String toString() {
233+
return engine.toString();
211234
}
212235

213-
public static <K1, K2, V> NestedMap2<K1, K2, V> createWithHashMaps() {
214-
return new NestedMap2<>(new NestedMap(HashMap::new));
236+
@Override
237+
public boolean equals(Object obj) {
238+
return engine.equals(((NestedMap2) obj).engine);
215239
}
216240

217-
public static <K1, K2, V> NestedMap2<K1, K2, V> createWithConcurrentHashMaps() {
218-
return new NestedMap2<>(new NestedMap(ConcurrentHashMap::new));
241+
@Override
242+
public int hashCode() {
243+
return engine.hashCode();
219244
}
220245

221246
public void put(K1 key1, K2 key2, V value) {
222247
engine.put(key1, key2, value);
223248
}
224249

225-
@SuppressWarnings("unchecked")
226250
public V get(K1 key1, K2 key2) {
227251
return (V) engine.get(key1, key2);
228252
}
229253

230-
@SuppressWarnings("unchecked")
231254
public V remove(K1 key1, K2 key2) {
232255
return (V) engine.remove(key1, key2);
233256
}
@@ -264,11 +287,6 @@ public Stream<Entry<K1, K2, V>> stream() {
264287
public ImmutableNestedMap2<K1, K2, V> createImmutable() {
265288
return new ImmutableNestedMap2<K1, K2, V>(engine);
266289
}
267-
268-
@Override
269-
public String toString() {
270-
return engine.toString();
271-
}
272290
}
273291

274292
public static class ImmutableNestedMap2<K1, K2, V> extends NestedMap2<K1, K2, V> {
@@ -291,22 +309,9 @@ private NestedMap3(NestedMap engine) {
291309
this.engine = engine;
292310
}
293311

294-
/**
295-
* Takes Treemap::new, HashMap::new, ConcurrentHashMap::new
296-
*
297-
* @param <K1>
298-
* @param <K2>
299-
* @param <K3>
300-
* @param <V>
301-
* @param supplier
302-
* @return
303-
*/
304-
public static <
305-
K1 extends Comparable<K1>,
306-
K2 extends Comparable<K2>,
307-
K3 extends Comparable<K3>,
308-
V>
309-
NestedMap3<K1, K2, K3, V> create(Supplier<Map<Object, Object>> supplier) {
312+
/** Takes Treemap::new, HashMap::new, ConcurrentHashMap::new, and other suppliers */
313+
public static <K1, K2, K3, V> NestedMap3<K1, K2, K3, V> create(
314+
Supplier<Map<Object, Object>> supplier) {
310315
return new NestedMap3<>(new NestedMap(supplier));
311316
}
312317

@@ -327,6 +332,16 @@ public String toString() {
327332
return engine.toString();
328333
}
329334

335+
@Override
336+
public boolean equals(Object obj) {
337+
return engine.equals(((NestedMap3) obj).engine);
338+
}
339+
340+
@Override
341+
public int hashCode() {
342+
return engine.hashCode();
343+
}
344+
330345
public static class Entry<K1, K2, K3, V> { // With Java17 we could use records
331346
List<Object> list;
332347

@@ -384,13 +399,7 @@ private NestedMap4(NestedMap engine) {
384399
this.engine = engine;
385400
}
386401

387-
public static <
388-
K1 extends Comparable<K1>,
389-
K2 extends Comparable<K2>,
390-
K3 extends Comparable<K3>,
391-
K4 extends Comparable<K4>,
392-
V>
393-
NestedMap4<K1, K2, K3, K4, V> createWithTreeMaps() {
402+
public static <K1, K2, K3, K4, V> NestedMap4<K1, K2, K3, K4, V> createWithTreeMaps() {
394403
return new NestedMap4<>(new NestedMap(TreeMap::new));
395404
}
396405

@@ -421,6 +430,9 @@ public V remove(K1 key1, K2 key2, K3 key3, K4 key4) {
421430
public String toString() {
422431
return engine.toString();
423432
}
433+
434+
// TODO finish up along the lines of NestedMap2
435+
424436
}
425437

426438
// --- SHIM FOR 5-LEVEL MAP ---
@@ -470,6 +482,8 @@ public V remove(K1 key1, K2 key2, K3 key3, K4 key4, K5 key5) {
470482
public String toString() {
471483
return engine.toString();
472484
}
485+
486+
// TODO finish up along the lines of NestedMap2
473487
}
474488

475489
// --- SHIM FOR 6-LEVEL MAP ---
@@ -480,14 +494,7 @@ private NestedMap6(NestedMap engine) {
480494
this.engine = engine;
481495
}
482496

483-
public static <
484-
K1 extends Comparable<K1>,
485-
K2 extends Comparable<K2>,
486-
K3 extends Comparable<K3>,
487-
K4 extends Comparable<K4>,
488-
K5 extends Comparable<K5>,
489-
K6 extends Comparable<K6>,
490-
V>
497+
public static <K1, K2, K3, K4, K5, K6, V>
491498
NestedMap6<K1, K2, K3, K4, K5, K6, V> createWithTreeMaps() {
492499
return new NestedMap6<>(new NestedMap(TreeMap::new));
493500
}
@@ -520,5 +527,8 @@ public V remove(K1 key1, K2 key2, K3 key3, K4 key4, K5 key5, K6 key6) {
520527
public String toString() {
521528
return engine.toString();
522529
}
530+
531+
// TODO finish up along the lines of NestedMap2
532+
523533
}
524534
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.unicode.cldr.unittest;
2+
3+
import com.google.common.collect.ImmutableMap;
4+
import java.util.ArrayList;
5+
import java.util.HashMap;
6+
import java.util.LinkedHashMap;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Map.Entry;
10+
import java.util.TreeMap;
11+
import java.util.concurrent.ConcurrentHashMap;
12+
import java.util.function.Supplier;
13+
import java.util.stream.Collectors;
14+
import org.unicode.cldr.icu.dev.test.TestFmwk;
15+
import org.unicode.cldr.util.Joiners;
16+
import org.unicode.cldr.util.NestedMap.ImmutableNestedMap2;
17+
import org.unicode.cldr.util.NestedMap.NestedMap2;
18+
19+
public class TestNestedMaps extends TestFmwk {
20+
public static void main(String[] args) {
21+
new TestNestedMaps().run(args);
22+
}
23+
24+
public void testBasic() {
25+
List<String> key1s = List.of("b", "a", "b");
26+
List<Double> key2s = List.of(993.2d, 5.3d, 99d);
27+
Boolean v1 = true;
28+
List<String> actualParts = List.of("[b, 993.2, true]", "[a, 5.3, true]", "[b, 99.0, true]");
29+
// tree order is 1,2,0
30+
31+
Map<Supplier<Map<Object, Object>>, List<Integer>> supplierAndOrders =
32+
ImmutableMap.of(
33+
TreeMap::new,
34+
List.of(1, 2, 0),
35+
LinkedHashMap::new,
36+
List.of(0, 2, 1), // keys are ordered together
37+
HashMap::new,
38+
List.of(1, 0, 2),
39+
ConcurrentHashMap::new,
40+
List.of(1, 0, 2));
41+
for (Entry<Supplier<Map<Object, Object>>, List<Integer>> supplierAndOrder :
42+
supplierAndOrders.entrySet()) {
43+
Supplier<Map<Object, Object>> supplier = supplierAndOrder.getKey();
44+
List<Integer> order = supplierAndOrder.getValue();
45+
46+
NestedMap2<String, Double, Boolean> nm2 = NestedMap2.create(supplier);
47+
48+
for (int i = 0; i < key1s.size(); ++i) {
49+
String key1 = key1s.get(i);
50+
Double key2 = key2s.get(i);
51+
String stringified = join(i, actualParts, order);
52+
nm2.put(key1, key2, v1);
53+
Boolean result = nm2.get(key1, key2);
54+
assertEquals(String.valueOf(i), v1, result);
55+
56+
String actual = Joiners.VBAR.join(nm2.stream().collect(Collectors.toList()));
57+
assertEquals(String.valueOf(i) + " " + order, stringified, actual);
58+
}
59+
60+
ImmutableNestedMap2<String, Double, Boolean> nm2_immutable = nm2.createImmutable();
61+
nm2.equals(nm2_immutable);
62+
if (!assertEquals("immutable equals?", nm2, nm2_immutable)) {}
63+
}
64+
}
65+
66+
private String join(int i, List<String> actualParts, List<Integer> order) {
67+
List<String> result = new ArrayList<>();
68+
for (int j : order) {
69+
if (j > i) continue;
70+
result.add(actualParts.get(j));
71+
}
72+
return Joiners.VBAR.join(result);
73+
}
74+
}

0 commit comments

Comments
 (0)