1 package org.opentrafficsim.core.gtu;
2
3 import java.util.Arrays;
4 import java.util.LinkedHashMap;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Set;
8 import java.util.function.Supplier;
9
10 import nl.tudelft.simulation.language.Throw;
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 public class NestedCache<T>
26 {
27
28
29 private final Class<?>[] types;
30
31
32 private final Map<Object, Object> map = new LinkedHashMap<>();
33
34
35
36
37
38 public NestedCache(final Class<?>... types)
39 {
40 this.types = types;
41 }
42
43
44
45
46
47
48
49 public T getValue(final Supplier<T> supplier, final Object... keys)
50 {
51 return getValue(supplier, Arrays.asList(keys));
52 }
53
54
55
56
57
58
59
60 @SuppressWarnings("unchecked")
61 private T getValue(final Supplier<T> supplier, final List<Object> keys)
62 {
63 Throw.when(keys.size() != this.types.length, IllegalArgumentException.class, "Incorrect number of keys.");
64 Throw.when(keys.get(0) != null && !this.types[0].isAssignableFrom(keys.get(0).getClass()),
65 IllegalArgumentException.class, "Key %s is not of %s.", keys.get(0), this.types[0]);
66 Object sub = this.map.get(keys.get(0));
67 if (this.types.length == 1)
68 {
69 if (sub == null)
70 {
71 sub = supplier.get();
72 this.map.put(keys.get(0), sub);
73 }
74 return (T) sub;
75 }
76 if (sub == null)
77 {
78
79 Class<Object>[] subTypes = new Class[this.types.length - 1];
80 System.arraycopy(this.types, 1, subTypes, 0, this.types.length - 1);
81 sub = new NestedCache<T>(subTypes);
82 this.map.put(keys.get(0), sub);
83 }
84
85 return ((NestedCache<T>) sub).getValue(supplier, keys.subList(1, keys.size()));
86 }
87
88
89
90
91
92 public Set<Object> getKeys()
93 {
94 return this.map.keySet();
95 }
96
97
98
99
100
101
102
103 @SuppressWarnings("unchecked")
104 public NestedCache<T> getChild(final Object key) throws IllegalStateException
105 {
106 Throw.when(this.types.length < 2, IllegalStateException.class, "Children can only be obtained on branch levels.");
107 return (NestedCache<T>) this.map.get(key);
108 }
109
110
111
112
113
114
115
116 @SuppressWarnings("unchecked")
117 public T getValue(final Object key) throws IllegalStateException
118 {
119 Throw.when(this.types.length != 1, IllegalStateException.class, "Values can only be obtained on leaf levels.");
120 return (T) this.map.get(key);
121 }
122
123
124 @Override
125 public String toString()
126 {
127 return "NestedCache [types=" + Arrays.toString(this.types) + ", map=" + this.map + "]";
128 }
129
130 }