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