]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/tests/framework/src/com/ibm/icu/dev/util/Relation.java
Added flags.
[Dictionary.git] / jars / icu4j-52_1 / main / tests / framework / src / com / ibm / icu / dev / util / Relation.java
1 /*
2  **********************************************************************
3  * Copyright (c) 2002-2012, International Business Machines
4  * Corporation and others.  All Rights Reserved.
5  **********************************************************************
6  * Author: Mark Davis
7  **********************************************************************
8  */
9 package com.ibm.icu.dev.util;
10
11 import java.lang.reflect.Constructor;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.HashMap;
17 import java.util.LinkedHashSet;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Set;
21
22 import com.ibm.icu.util.Freezable;
23
24 /**
25  * A Relation is a set of mappings from keys to values.
26  * Unlike Map, there is not guaranteed to be a single value per key.
27  * The Map-like APIs return collections for values.
28  * @author medavis
29
30  */
31 public class Relation<K, V> implements Freezable { // TODO: add , Map<K, Collection<V>>, but requires API changes
32     private Map<K, Set<V>> data;
33
34     Constructor<Set<V>> setCreator;
35     Object[] setComparatorParam;
36
37     public static <K,V> Relation<K, V> of(Map<K, Set<V>> map, Class<?> setCreator) {
38         return new Relation(map, setCreator);
39     }
40
41     public static <K,V> Relation<K, V> of(Map<K, Set<V>> map, Class setCreator, Comparator<V> setComparator) {
42         return new Relation(map, setCreator, setComparator);
43     }
44
45     public Relation(Map<K, Set<V>> map, Class<Set<V>> setCreator) {
46         this(map, setCreator, null);
47     }
48
49     public Relation(Map<K, Set<V>> map, Class<Set<V>> setCreator, Comparator<V> setComparator) {
50         try {
51             setComparatorParam = setComparator == null ? null : new Object[]{setComparator};
52             if (setComparator == null) {
53                 this.setCreator = setCreator.getConstructor();
54                 this.setCreator.newInstance(setComparatorParam); // check to make sure compiles
55             } else {
56                 this.setCreator = setCreator.getConstructor(Comparator.class);
57                 this.setCreator.newInstance(setComparatorParam); // check to make sure compiles        
58             }
59             data = map == null ? new HashMap() : map;     
60         } catch (Exception e) {
61             throw (RuntimeException) new IllegalArgumentException("Can't create new set").initCause(e);
62         }
63     }
64
65     public void clear() {
66         data.clear();
67     }
68
69     public boolean containsKey(Object key) {
70         return data.containsKey(key);
71     }
72
73     public boolean containsValue(Object value) {
74         for (Set<V> values : data.values()) {
75             if (values.contains(value)) {
76                 return true;
77             }
78         }
79         return false;
80     }
81
82     public final Set<Entry<K, V>> entrySet() {
83         return keyValueSet();
84     }
85     
86     public Set<Entry<K, Set<V>>> keyValuesSet() {
87         return data.entrySet();
88     }
89     
90     public Set<Entry<K, V>> keyValueSet() {
91         Set<Entry<K, V>> result = new LinkedHashSet();
92         for (K key : data.keySet()) {
93             for (V value : data.get(key)) {
94                 result.add(new SimpleEntry(key, value));
95             }
96         }
97         return result;
98     }
99
100     public boolean equals(Object o) {
101         if (o == null)
102             return false;
103         if (o.getClass() != this.getClass())
104             return false;
105         return data.equals(((Relation) o).data);
106     }
107
108     //  public V get(Object key) {
109     //      Set<V> set = data.get(key);
110     //      if (set == null || set.size() == 0)
111     //        return null;
112     //      return set.iterator().next();
113     //  }
114
115     public Set<V> getAll(Object key) {
116         return data.get(key);
117     }
118
119     public Set<V> get(Object key) {
120         return data.get(key);
121     }
122
123     public int hashCode() {
124         return data.hashCode();
125     }
126
127     public boolean isEmpty() {
128         return data.isEmpty();
129     }
130
131     public Set<K> keySet() {
132         return data.keySet();
133     }
134
135     public V put(K key, V value) {
136         Set<V> set = data.get(key);
137         if (set == null) {
138             data.put(key, set = newSet());
139         }
140         set.add(value);
141         return value;
142     }
143
144     public V putAll(K key, Collection<? extends V> values) {
145         Set<V> set = data.get(key);
146         if (set == null) {
147             data.put(key, set = newSet());
148         }
149         set.addAll(values);
150         return values.size() == 0 ? null : values.iterator().next();
151     }
152
153     public V putAll(Collection<K> keys, V value) {
154         V result = null;
155         for (K key : keys) {
156             result = put(key, value);
157         }
158         return result;
159     }
160
161     private Set<V> newSet() {
162         try {
163             return (Set<V>) setCreator.newInstance(setComparatorParam);
164         } catch (Exception e) {
165             throw (RuntimeException) new IllegalArgumentException("Can't create new set").initCause(e);
166         }
167     }
168
169     public void putAll(Map<? extends K, ? extends V> t) {
170         for (K key : t.keySet()) {
171             put(key, t.get(key));
172         }
173     }
174
175     public void putAll(Relation<? extends K, ? extends V> t) {
176         for (K key : t.keySet()) {
177             for (V value : t.getAll(key)) {
178                 put(key, value);
179             }
180         }
181     }
182
183     public Set<V> removeAll(K key) {
184         try {
185             return data.remove(key);
186         } catch (NullPointerException e) {
187             return null; // data doesn't allow null, eg ConcurrentHashMap
188         }
189     }
190
191     public boolean remove(K key, V value) {
192         try {
193             Set<V> set = data.get(key);
194             if (set == null) {
195                 return false;
196             }
197             boolean result = set.remove(value);
198             if (set.size() == 0) {
199                 data.remove(key);
200             }
201             return result;
202         } catch (NullPointerException e) {
203             return false; // data doesn't allow null, eg ConcurrentHashMap
204         }
205     }
206
207     public int size() {
208         return data.size();
209     }
210
211     public Set<V> values() {
212         return values(new LinkedHashSet());
213     }
214
215     public <C extends Collection<V>> C values(C result) {
216         for (Entry<K, Set<V>> keyValue : data.entrySet()) {
217             result.addAll(keyValue.getValue());
218         }
219         return result;
220     }
221
222     public String toString() {
223         return data.toString();
224     }
225
226     static class SimpleEntry<K, V> implements Entry<K, V> {
227         K key;
228
229         V value;
230
231         public SimpleEntry(K key, V value) {
232             this.key = key;
233             this.value = value;
234         }
235
236         public SimpleEntry(Entry<K, V> e) {
237             this.key = e.getKey();
238             this.value = e.getValue();
239         }
240
241         public K getKey() {
242             return key;
243         }
244
245         public V getValue() {
246             return value;
247         }
248
249         public V setValue(V value) {
250             V oldValue = this.value;
251             this.value = value;
252             return oldValue;
253         }
254     }
255
256     public Relation<K,V> addAllInverted(Relation<V,K> source) {
257         for (V value : source.data.keySet()) {
258             for (K key : source.data.get(value)) {
259                 put(key, value);
260             }
261         }
262         return this;
263     }
264
265     public Relation<K,V> addAllInverted(Map<V,K> source) {
266         for (V value : source.keySet()) {
267             put(source.get(value), value);
268         }
269         return this;
270     }
271
272     boolean frozen = false;
273
274     public boolean isFrozen() {
275         return frozen;
276     }
277
278     public Object freeze() {
279         if (!frozen) {
280             frozen = true;
281             // does not handle one level down, so we do that on a case-by-case basis
282             for (K key : data.keySet()) {
283                 data.put(key, Collections.unmodifiableSet(data.get(key)));
284             }
285             // now do top level
286             data = Collections.unmodifiableMap(data);
287         }
288         return this;
289     }
290
291     public Object cloneAsThawed() {
292         // TODO do later
293         throw new UnsupportedOperationException();
294     }
295
296     public boolean removeAll(Relation<K, V> toBeRemoved) {
297         boolean result = false;
298         for (K key : toBeRemoved.keySet()) {
299             try {
300                 Set<V> values = toBeRemoved.getAll(key);
301                 if (values != null) {
302                     result |= removeAll(key, values);
303                 }
304             } catch (NullPointerException e) {
305                 // data doesn't allow null, eg ConcurrentHashMap
306             }
307         }
308         return result;
309     }
310
311     public Set<V> removeAll(K... keys) {
312         return removeAll(Arrays.asList(keys));
313     }
314
315     public boolean removeAll(K key, Iterable<V> toBeRemoved) {
316         boolean result = false;
317         for (V value : toBeRemoved) {
318             result |= remove(key, value);
319         }
320         return result;
321     }
322
323     public Set<V> removeAll(Collection<K> toBeRemoved) {
324         Set<V> result = new LinkedHashSet();
325         for (K key : toBeRemoved) {
326             try {
327                 final Set<V> removals = data.remove(key);
328                 if (removals != null) {
329                     result.addAll(removals);
330                 }
331             } catch (NullPointerException e) {
332                 // data doesn't allow null, eg ConcurrentHashMap
333             }
334         }
335         return result;
336     }
337 }