1 package org.unicode.cldr.util; 2 3 import java.lang.reflect.Constructor; 4 import java.util.ArrayList; 5 import java.util.Collections; 6 import java.util.HashMap; 7 import java.util.Iterator; 8 import java.util.List; 9 import java.util.Map; 10 import java.util.Map.Entry; 11 import java.util.Set; 12 import java.util.TreeMap; 13 14 import com.ibm.icu.impl.Row; 15 import com.ibm.icu.impl.Row.R3; 16 import com.ibm.icu.impl.Row.R4; 17 import com.ibm.icu.impl.Row.R5; 18 19 public class ChainedMap { 20 21 public static class M3<K2, K1, V> extends ChainedMap implements Iterable<Map.Entry<K2, Map<K1, V>>> { 22 @SuppressWarnings("unchecked") 23 private M3(Map<K2, Object> map2, Map<K1, Object> map1, Class<V> valueClass) { 24 super(map2, map1); 25 } 26 27 private M3(Map<?, ?> map2, Constructor<Map<Object, Object>>[] constructors, int indexStart) { 28 super(map2, constructors, indexStart); 29 } 30 31 @SuppressWarnings("unchecked") 32 public V get(K2 key2, K1 key1) { 33 return (V) super.handleGet(key2, key1); 34 } 35 36 @SuppressWarnings("unchecked") 37 public Map<K1, V> get(K2 key2) { 38 Map<K1, V> map = (Map<K1, V>) super.mapBase.get(key2); 39 return map == null ? null : Collections.unmodifiableMap(map); 40 } 41 42 @SuppressWarnings("unchecked") 43 public V put(K2 key2, K1 key1, V value) { 44 return (V) super.handlePut(value, key2, key1); 45 } 46 47 @SuppressWarnings("unchecked") 48 @Override 49 public Iterator<Entry<K2, Map<K1, V>>> iterator() { 50 return (Iterator<Entry<K2, Map<K1, V>>>) super.iterator(); 51 } 52 53 @SuppressWarnings("unchecked") 54 public Iterable<Row.R3<K2, K1, V>> rows() { 55 List<R3<K2, K1, V>> result = new ArrayList<R3<K2, K1, V>>(); 56 for (Entry<Object, Object> entry0 : super.mapBase.entrySet()) { 57 for (Entry<Object, Object> entry1 : ((Map<Object, Object>) entry0.getValue()).entrySet()) { 58 R3<K2, K1, V> item = (R3<K2, K1, V>) Row.of(entry0.getKey(), entry1.getKey(), entry1.getValue()); 59 result.add(item); 60 } 61 } 62 return result; 63 } 64 65 @SuppressWarnings("unchecked") 66 public Set<K2> keySet() { 67 return (Set<K2>) super.mapBase.keySet(); 68 } 69 } 70 71 public static class M4<K3, K2, K1, V> extends ChainedMap implements Iterable<Map.Entry<K3, Map<K2, Map<K1, V>>>> { 72 @SuppressWarnings("unchecked") 73 private M4(Map<K3, Object> map3, Map<K2, Object> map2, Map<K1, Object> map1, Class<V> valueClass) { 74 super(map3, map2, map1); 75 } 76 77 private M4(Map<?, ?> map2, Constructor<Map<Object, Object>>[] constructors, int indexStart) { 78 super(map2, constructors, indexStart); 79 } 80 81 @SuppressWarnings("unchecked") 82 public V get(K3 key3, K2 key2, K1 key1) { 83 return (V) super.handleGet(key3, key2, key1); 84 } 85 86 public M3<K2, K1, V> get(K3 key3) { 87 final Map<?, ?> submap = (Map<?, ?>) super.handleGet(key3); 88 return submap == null ? null : new M3<K2, K1, V>(submap, super.mapConstructors, super.indexStart + 1); 89 } 90 91 @SuppressWarnings("unchecked") 92 public V put(K3 key3, K2 key2, K1 key1, V value) { 93 return (V) super.handlePut(value, key3, key2, key1); 94 } 95 96 @SuppressWarnings("unchecked") 97 @Override 98 public Iterator<Entry<K3, Map<K2, Map<K1, V>>>> iterator() { 99 return (Iterator<Entry<K3, Map<K2, Map<K1, V>>>>) super.iterator(); 100 } 101 102 @SuppressWarnings("unchecked") 103 public Iterable<Row.R4<K3, K2, K1, V>> rows() { 104 List<R4<K3, K2, K1, V>> result = new ArrayList<R4<K3, K2, K1, V>>(); 105 for (Entry<Object, Object> entry0 : super.mapBase.entrySet()) { 106 for (Entry<Object, Object> entry1 : ((Map<Object, Object>) entry0.getValue()).entrySet()) { 107 for (Entry<Object, Object> entry2 : ((Map<Object, Object>) entry1.getValue()).entrySet()) { 108 R4<K3, K2, K1, V> item = (R4<K3, K2, K1, V>) Row.of(entry0.getKey(), entry1.getKey(), entry2.getKey(), entry2.getValue()); 109 result.add(item); 110 } 111 } 112 } 113 return result; 114 } 115 116 @SuppressWarnings("unchecked") 117 public Set<K3> keySet() { 118 return (Set<K3>) super.mapBase.keySet(); 119 } 120 } 121 122 public static class M5<K4, K3, K2, K1, V> extends ChainedMap implements Iterable<Map.Entry<K4, Map<K3, Map<K2, Map<K1, V>>>>> { 123 @SuppressWarnings("unchecked") 124 private M5(Map<K4, Object> map4, Map<K3, Object> map3, Map<K2, Object> map2, Map<K1, Object> map1, Class<V> valueClass) { 125 super(map4, map3, map2, map1); 126 } 127 128 @SuppressWarnings("unchecked") 129 public V get(K4 key4, K3 key3, K2 key2, K1 key1) { 130 return (V) super.handleGet(key4, key3, key2, key1); 131 } 132 133 public M4<K3, K2, K1, V> get(K4 key4) { 134 final Map<?, ?> submap = (Map<?, ?>) super.handleGet(key4); 135 return submap == null ? null 136 : new M4<K3, K2, K1, V>(submap, super.mapConstructors, super.indexStart + 2); 137 } 138 139 @SuppressWarnings("unchecked") 140 public V put(K4 key4, K3 key3, K2 key2, K1 key1, V value) { 141 return (V) super.handlePut(value, key4, key3, key2, key1); 142 } 143 144 @SuppressWarnings("unchecked") 145 @Override 146 public Iterator<Entry<K4, Map<K3, Map<K2, Map<K1, V>>>>> iterator() { 147 return (Iterator<Entry<K4, Map<K3, Map<K2, Map<K1, V>>>>>) super.iterator(); 148 } 149 150 @SuppressWarnings("unchecked") 151 public Iterable<Row.R5<K4, K3, K2, K1, V>> rows() { 152 List<R5<K4, K3, K2, K1, V>> result = new ArrayList<R5<K4, K3, K2, K1, V>>(); 153 for (Entry<Object, Object> entry0 : super.mapBase.entrySet()) { 154 for (Entry<Object, Object> entry1 : ((Map<Object, Object>) entry0.getValue()).entrySet()) { 155 for (Entry<Object, Object> entry2 : ((Map<Object, Object>) entry1.getValue()).entrySet()) { 156 for (Entry<Object, Object> entry3 : ((Map<Object, Object>) entry2.getValue()).entrySet()) { 157 R5<K4, K3, K2, K1, V> item = (R5<K4, K3, K2, K1, V>) Row.of( 158 entry0.getKey(), entry1.getKey(), entry2.getKey(), entry3.getKey(), entry3.getValue()); 159 result.add(item); 160 } 161 } 162 } 163 } 164 return result; 165 } 166 167 @SuppressWarnings("unchecked") 168 public Set<K4> keySet() { 169 return (Set<K4>) super.mapBase.keySet(); 170 } 171 } 172 173 private final Map<Object, Object> mapBase; 174 private final Constructor<Map<Object, Object>>[] mapConstructors; 175 private final int indexStart; 176 177 @SuppressWarnings("unchecked") 178 private ChainedMap(Map<? extends Object, ? extends Object>... maps) { 179 this(maps[0], constructorList(maps), 0); 180 } 181 182 @SuppressWarnings("unchecked") 183 private ChainedMap(Map<?, ?> mapBase, Constructor<Map<Object, Object>>[] mapConstructors, int indexStart) { 184 this.mapBase = (Map<Object, Object>) mapBase; 185 this.mapConstructors = mapConstructors; 186 this.indexStart = indexStart; 187 } 188 189 @SuppressWarnings("unchecked") 190 private static Constructor<Map<Object, Object>>[] constructorList(Map<? extends Object, ? extends Object>... maps) { 191 Constructor<Map<Object, Object>>[] tempMapConstructors = new Constructor[maps.length - 1]; 192 items: for (int i = 0; i < maps.length - 1; ++i) { 193 for (Constructor<?> constructor : maps[i + 1].getClass().getConstructors()) { 194 if (constructor.getParameterTypes().length == 0) { 195 tempMapConstructors[i] = (Constructor<Map<Object, Object>>) constructor; 196 continue items; 197 } 198 } 199 throw new IllegalArgumentException("Couldn't create empty constructor for " + maps[i]); 200 } 201 return tempMapConstructors; 202 } 203 204 public static <T> Constructor<T> getEmptyConstructor(Class<T> c) { 205 for (Constructor<?> constructor : c.getConstructors()) { 206 if (constructor.getParameterTypes().length == 0) { 207 return (Constructor<T>) constructor; 208 } 209 } 210 return null; 211 } 212 213 public static <K2, K1, V> M3<K2, K1, V> of(Map<K2, Object> map2, Map<K1, Object> map1, Class<V> valueClass) { 214 return new M3<K2, K1, V>(map2, map1, valueClass); 215 } 216 217 public static <K3, K2, K1, V> M4<K3, K2, K1, V> of(Map<K3, Object> map3, Map<K2, Object> map2, Map<K1, Object> map1, Class<V> valueClass) { 218 return new M4<K3, K2, K1, V>(map3, map2, map1, valueClass); 219 } 220 221 public static <K4, K3, K2, K1, V> M5<K4, K3, K2, K1, V> of( 222 Map<K4, Object> map4, Map<K3, Object> map3, Map<K2, Object> map2, Map<K1, Object> map1, Class<V> valueClass) { 223 return new M5<K4, K3, K2, K1, V>(map4, map3, map2, map1, valueClass); 224 } 225 226 private Object iterator() { 227 return mapBase.entrySet().iterator(); 228 } 229 230 public void clear() { 231 mapBase.clear(); 232 } 233 234 @SuppressWarnings("unchecked") 235 private Object handleGet(Object... keys) { 236 Map<Object, Object> map = mapBase; 237 int last = keys.length - 1; 238 for (int i = 0; i < last; ++i) { 239 Object key = keys[i]; 240 map = (Map<Object, Object>) map.get(key); 241 if (map == null) { 242 return null; 243 } 244 } 245 return map.get(keys[last]); 246 } 247 248 @SuppressWarnings("unchecked") 249 private Object handlePut(Object value, Object... keys) { 250 Map<Object, Object> map = mapBase; 251 int last = keys.length - 1; 252 for (int i = indexStart; i < last; ++i) { 253 Object key = keys[i]; 254 Map<Object, Object> map2 = (Map<Object, Object>) map.get(key); 255 if (map2 == null) { 256 try { 257 map.put(key, map2 = mapConstructors[i].newInstance()); 258 } catch (Exception e) { 259 throw new IllegalArgumentException("Cannot create map with " + mapConstructors[i], e); 260 } 261 } 262 map = map2; 263 } 264 return value == null ? map.remove(keys[last]) : map.put(keys[last], value); 265 } 266 267 @Override 268 public String toString() { 269 return mapBase.toString(); 270 } 271 272 public static void main(String[] args) { 273 M5<Boolean, Byte, String, Integer, Double> foo = ChainedMap.of( 274 new TreeMap<Boolean, Object>(), 275 new HashMap<Byte, Object>(), 276 new TreeMap<String, Object>(), 277 new TreeMap<Integer, Object>(), 278 Double.class); 279 280 System.out.println(foo.put(true, (byte) 0, "abc", 3, 1.5)); 281 System.out.println(foo.get(true, (byte) 0, "abc", 3)); 282 283 System.out.println(foo.put(false, (byte) 0, "Def", 3, 1.5)); 284 System.out.println(foo.put(true, (byte) -1, "ghi", 3, 2.0)); 285 System.out.println(foo.put(true, (byte) 0, "ghi", 3, 3.0)); 286 System.out.println(foo.put(true, (byte) 0, "abc", 4, 1.5)); 287 288 for (Entry<Boolean, Map<Byte, Map<String, Map<Integer, Double>>>> entry : foo) { 289 System.out.println("entries: " + entry); 290 } 291 for (R5<Boolean, Byte, String, Integer, Double> entry : foo.rows()) { 292 System.out.println("rows: " + entry); 293 } 294 } 295 } 296