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> {
make()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 
UnicodeRelation(SetMaker<T> maker)38     public UnicodeRelation(SetMaker<T> maker) {
39         this.maker = maker;
40     }
41 
UnicodeRelation()42     public UnicodeRelation() {
43         this.maker = (SetMaker<T>) HASHSET_MAKER;
44     }
45 
size()46     public int size() {
47         return data.size();
48     }
49 
isEmpty()50     public boolean isEmpty() {
51         return data.isEmpty();
52     }
53 
containsKey(int key)54     public boolean containsKey(int key) {
55         return data.containsKey(key);
56     }
57 
containsKey(String key)58     public boolean containsKey(String key) {
59         return data.containsKey(key);
60     }
61 
containsValue(T value)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 
get(int key)71     public Set<T> get(int key) {
72         return data.get(key);
73     }
74 
get(String key)75     public Set<T> get(String key) {
76         return data.get((String) key);
77     }
78 
getKeys(T value)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 
add(String key, T value)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 
add(int key, T value)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 
addAll(String key, Collection<T> values)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 
addAll(Map<String, T> m)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 
addAll(UnicodeSet keys, Collection<T> values)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 
addAll(UnicodeSet keys, T... values)127     public UnicodeRelation<T> addAll(UnicodeSet keys, T... values) {
128         return addAll(keys, Arrays.asList(values));
129     }
130 
addAll(UnicodeSet keys, T value)131     public UnicodeRelation<T> addAll(UnicodeSet keys, T value) {
132         for (String key : keys) {
133             add(key, value);
134         }
135         return this;
136     }
137 
addValue(Set<T> oldValues, T value)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 
make(Collection<T> oldValues)150     private final Set<T> make(Collection<T> oldValues) {
151         Set<T> newValues = maker.make();
152         newValues.addAll(oldValues);
153         return newValues;
154     }
155 
addValues(Set<T> oldValues, Collection<T> values)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 
removeValues(Set<T> oldValues, Collection<T> values)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 
remove(int key)184     public UnicodeRelation<T> remove(int key) {
185         data.remove(key);
186         return this;
187     }
188 
remove(String key)189     public UnicodeRelation<T> remove(String key) {
190         data.remove(key);
191         return this;
192     }
193 
removeValue(T value)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 
remove(int key, T value)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 
remove(String key, T value)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 
removeAll(String key, Collection<T> values)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 
removeAll(Map<String, T> m)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 
removeAll(UnicodeSet keys, Collection<T> values)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 
removeAll(UnicodeSet keys, T... values)244     public UnicodeRelation<T> removeAll(UnicodeSet keys, T... values) {
245         return removeAll(keys, Arrays.asList(values));
246     }
247 
removeAll(UnicodeSet keys, T value)248     public UnicodeRelation<T> removeAll(UnicodeSet keys, T value) {
249         for (String key : keys) {
250             remove(key, value);
251         }
252         return this;
253     }
254 
removeExisting(int key, T value, Set<T> values)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 
removeExisting(String key, T value, Set<T> values)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 
clear()275     public void clear() {
276         data.clear();
277     }
278 
keySet()279     public UnicodeSet keySet() {
280         return data.keySet();
281     }
282 
values()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 
keyValues()291     public Iterable<Entry<String, Set<T>>> keyValues() {
292         return data.entrySet();
293     }
294 
295     @Override
toString()296     public String toString() {
297         return data.toString();
298     }
299 
300     @Override
hashCode()301     public int hashCode() {
302         return data.hashCode();
303     }
304 
305     @Override
equals(Object obj)306     public boolean equals(Object obj) {
307         return obj instanceof UnicodeRelation && data.equals(((UnicodeRelation) obj).data);
308     }
309 
310     @Override
isFrozen()311     public boolean isFrozen() {
312         return data.isFrozen();
313     }
314 
315     @Override
freeze()316     public UnicodeRelation<T> freeze() {
317         data.freeze();
318         return this;
319     }
320 
321     @Override
cloneAsThawed()322     public UnicodeRelation<T> cloneAsThawed() {
323         throw new UnsupportedOperationException();
324     }
325 }
326