Home | History | Annotate | Download | only in util
      1 package org.unicode.cldr.util;
      2 
      3 import java.util.Arrays;
      4 import java.util.Collection;
      5 import java.util.Collections;
      6 import java.util.HashSet;
      7 import java.util.LinkedHashSet;
      8 import java.util.Map;
      9 import java.util.Map.Entry;
     10 import java.util.Set;
     11 
     12 import com.ibm.icu.dev.util.UnicodeMap;
     13 import com.ibm.icu.text.UnicodeSet;
     14 import com.ibm.icu.util.Freezable;
     15 
     16 public class UnicodeRelation<T> implements Freezable<UnicodeRelation<T>> {
     17 
     18     final UnicodeMap<Set<T>> data = new UnicodeMap<>();
     19     final SetMaker<T> maker;
     20 
     21     public interface SetMaker<T> {
     22         Set<T> make();
     23     }
     24 
     25     public static SetMaker<Object> HASHSET_MAKER = new SetMaker<Object>() {
     26         @Override
     27         public Set<Object> make() {
     28             return new HashSet<Object>();
     29         }
     30     };
     31 
     32     public static final SetMaker<Object> LINKED_HASHSET_MAKER = new SetMaker<Object>() {
     33         public Set<Object> make() {
     34             return new LinkedHashSet<Object>();
     35         }
     36     };
     37 
     38     public UnicodeRelation(SetMaker<T> maker) {
     39         this.maker = maker;
     40     }
     41 
     42     public UnicodeRelation() {
     43         this.maker = (SetMaker<T>) HASHSET_MAKER;
     44     }
     45 
     46     public int size() {
     47         return data.size();
     48     }
     49 
     50     public boolean isEmpty() {
     51         return data.isEmpty();
     52     }
     53 
     54     public boolean containsKey(int key) {
     55         return data.containsKey(key);
     56     }
     57 
     58     public boolean containsKey(String key) {
     59         return data.containsKey(key);
     60     }
     61 
     62     public boolean containsValue(T value) {
     63         for (Set<T> v : data.values()) {
     64             if (v.contains(value)) {
     65                 return true;
     66             }
     67         }
     68         return false;
     69     }
     70 
     71     public Set<T> get(int key) {
     72         return data.get(key);
     73     }
     74 
     75     public Set<T> get(String key) {
     76         return data.get((String) key);
     77     }
     78 
     79     public UnicodeSet getKeys(T value) {
     80         UnicodeSet result = new UnicodeSet();
     81         for (Entry<String, Set<T>> entry : data.entrySet()) {
     82             if (entry.getValue().contains(value)) {
     83                 result.add(entry.getKey());
     84             }
     85         }
     86         return result;
     87     }
     88 
     89     public UnicodeRelation<T> add(String key, T value) {
     90         Set<T> newValues = addValue(data.get(key), value);
     91         if (newValues != null) {
     92             data.put(key, newValues);
     93         }
     94         return this;
     95     }
     96 
     97     public UnicodeRelation<T> add(int key, T value) {
     98         Set<T> newValues = addValue(data.get(key), value);
     99         if (newValues != null) {
    100             data.put(key, newValues);
    101         }
    102         return this;
    103     }
    104 
    105     public UnicodeRelation<T> addAll(String key, Collection<T> values) {
    106         Set<T> newValues = addValues(data.get(key), values);
    107         if (newValues != null) {
    108             data.put(key, newValues);
    109         }
    110         return this;
    111     }
    112 
    113     public UnicodeRelation<T> addAll(Map<String, T> m) {
    114         for (Entry<String, T> entry : m.entrySet()) {
    115             add(entry.getKey(), entry.getValue());
    116         }
    117         return this;
    118     }
    119 
    120     public UnicodeRelation<T> addAll(UnicodeSet keys, Collection<T> values) {
    121         for (String key : keys) {
    122             addAll(key, values);
    123         }
    124         return this;
    125     }
    126 
    127     public UnicodeRelation<T> addAll(UnicodeSet keys, T... values) {
    128         return addAll(keys, Arrays.asList(values));
    129     }
    130 
    131     public UnicodeRelation<T> addAll(UnicodeSet keys, T value) {
    132         for (String key : keys) {
    133             add(key, value);
    134         }
    135         return this;
    136     }
    137 
    138     private Set<T> addValue(Set<T> oldValues, T value) {
    139         if (oldValues == null) {
    140             return Collections.singleton(value);
    141         } else if (oldValues.contains(value)) {
    142             return null;
    143         } else {
    144             Set<T> newValues = make(oldValues);
    145             newValues.add(value);
    146             return Collections.unmodifiableSet(newValues);
    147         }
    148     }
    149 
    150     private final Set<T> make(Collection<T> oldValues) {
    151         Set<T> newValues = maker.make();
    152         newValues.addAll(oldValues);
    153         return newValues;
    154     }
    155 
    156     private Set<T> addValues(Set<T> oldValues, Collection<T> values) {
    157         if (oldValues == null) {
    158             if (values.size() == 1) {
    159                 return Collections.singleton(values.iterator().next());
    160             } else {
    161                 return Collections.unmodifiableSet(make(values));
    162             }
    163         } else if (oldValues.containsAll(values)) {
    164             return null;
    165         } else {
    166             Set<T> newValues = make(oldValues);
    167             newValues.addAll(values);
    168             return Collections.unmodifiableSet(newValues);
    169         }
    170     }
    171 
    172     private Set<T> removeValues(Set<T> oldValues, Collection<T> values) {
    173         if (oldValues == null) {
    174             return null;
    175         } else if (Collections.disjoint(oldValues, values)) {
    176             return null;
    177         } else {
    178             Set<T> newValues = make(oldValues);
    179             newValues.removeAll(values);
    180             return newValues.size() == 0 ? Collections.EMPTY_SET : Collections.unmodifiableSet(newValues);
    181         }
    182     }
    183 
    184     public UnicodeRelation<T> remove(int key) {
    185         data.remove(key);
    186         return this;
    187     }
    188 
    189     public UnicodeRelation<T> remove(String key) {
    190         data.remove(key);
    191         return this;
    192     }
    193 
    194     public UnicodeRelation<T> removeValue(T value) {
    195         UnicodeSet toChange = getKeys(value);
    196         for (String key : toChange) {
    197             remove(key, value);
    198         }
    199         return this;
    200     }
    201 
    202     public UnicodeRelation<T> remove(int key, T value) {
    203         Set<T> values = data.getValue(key);
    204         if (values != null && values.contains(value)) {
    205             removeExisting(key, value, values);
    206         }
    207         return this;
    208     }
    209 
    210     public UnicodeRelation<T> remove(String key, T value) {
    211         Set<T> values = data.getValue(key);
    212         if (values != null && values.contains(value)) {
    213             removeExisting(key, value, values);
    214         }
    215         return this;
    216     }
    217 
    218     public UnicodeRelation<T> removeAll(String key, Collection<T> values) {
    219         Set<T> newValues = removeValues(data.get(key), values);
    220         if (newValues != null) {
    221             if (newValues == Collections.EMPTY_SET) {
    222                 data.remove(key);
    223             } else {
    224                 data.put(key, newValues);
    225             }
    226         }
    227         return this;
    228     }
    229 
    230     public UnicodeRelation<T> removeAll(Map<String, T> m) {
    231         for (Entry<String, T> entry : m.entrySet()) {
    232             remove(entry.getKey(), entry.getValue());
    233         }
    234         return this;
    235     }
    236 
    237     public UnicodeRelation<T> removeAll(UnicodeSet keys, Collection<T> values) {
    238         for (String key : keys) {
    239             removeAll(key, values);
    240         }
    241         return this;
    242     }
    243 
    244     public UnicodeRelation<T> removeAll(UnicodeSet keys, T... values) {
    245         return removeAll(keys, Arrays.asList(values));
    246     }
    247 
    248     public UnicodeRelation<T> removeAll(UnicodeSet keys, T value) {
    249         for (String key : keys) {
    250             remove(key, value);
    251         }
    252         return this;
    253     }
    254 
    255     private void removeExisting(int key, T value, Set<T> values) {
    256         if (values.size() == 1) {
    257             data.remove(key);
    258         } else {
    259             Set<T> newValues = make(values);
    260             newValues.remove(value);
    261             data.put(key, Collections.unmodifiableSet(newValues));
    262         }
    263     }
    264 
    265     private void removeExisting(String key, T value, Set<T> values) {
    266         if (values.size() == 1) {
    267             data.remove(key);
    268         } else {
    269             Set<T> newValues = make(values);
    270             newValues.remove(value);
    271             data.put(key, Collections.unmodifiableSet(newValues));
    272         }
    273     }
    274 
    275     public void clear() {
    276         data.clear();
    277     }
    278 
    279     public UnicodeSet keySet() {
    280         return data.keySet();
    281     }
    282 
    283     public Collection<T> values() {
    284         Set<T> result = maker.make();
    285         for (Set<T> v : data.values()) {
    286             result.addAll(v);
    287         }
    288         return result;
    289     }
    290 
    291     public Iterable<Entry<String, Set<T>>> keyValues() {
    292         return data.entrySet();
    293     }
    294 
    295     @Override
    296     public String toString() {
    297         return data.toString();
    298     }
    299 
    300     @Override
    301     public int hashCode() {
    302         return data.hashCode();
    303     }
    304 
    305     @Override
    306     public boolean equals(Object obj) {
    307         return obj instanceof UnicodeRelation && data.equals(((UnicodeRelation) obj).data);
    308     }
    309 
    310     @Override
    311     public boolean isFrozen() {
    312         return data.isFrozen();
    313     }
    314 
    315     @Override
    316     public UnicodeRelation<T> freeze() {
    317         data.freeze();
    318         return this;
    319     }
    320 
    321     @Override
    322     public UnicodeRelation<T> cloneAsThawed() {
    323         throw new UnsupportedOperationException();
    324     }
    325 }
    326