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