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