Home | History | Annotate | Download | only in util
      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