]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/MapList.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.utils.datastructures / src / org / simantics / utils / datastructures / MapList.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 /*\r
13  * 16.8.2006\r
14  */\r
15 package org.simantics.utils.datastructures;\r
16 \r
17 import gnu.trove.map.hash.THashMap;\r
18 \r
19 import java.util.ArrayList;\r
20 import java.util.Collection;\r
21 import java.util.Collections;\r
22 import java.util.List;\r
23 import java.util.Map;\r
24 import java.util.Map.Entry;\r
25 import java.util.Set;\r
26 \r
27 /**\r
28  * MapList is a data structure with map on left side and arraylist on right side.\r
29  * <p>\r
30  * \r
31  * @author Toni Kalajainen\r
32  */\r
33 public class MapList<L, R> {\r
34 \r
35     @SuppressWarnings("rawtypes")\r
36     public static final MapList EMPTY_MAPLIST = new MapList() {\r
37         private static final String IMMUTABLE_MSG = "Cannot modify immutable empty MapList";\r
38 \r
39         @Override\r
40         public void add(Object key) {\r
41             throw new UnsupportedOperationException(IMMUTABLE_MSG);\r
42         }\r
43         @Override\r
44         public void add(Object key, int index, Object value) {\r
45             throw new UnsupportedOperationException(IMMUTABLE_MSG);\r
46         }\r
47         @Override\r
48         public void add(Object key, Object value) {\r
49             throw new UnsupportedOperationException(IMMUTABLE_MSG);\r
50         }\r
51         @Override\r
52         public void addAll(Object key, Collection values) {\r
53             throw new UnsupportedOperationException(IMMUTABLE_MSG);\r
54         }\r
55         @Override\r
56         public void clear() {\r
57             throw new UnsupportedOperationException(IMMUTABLE_MSG);\r
58         }\r
59         @Override\r
60         public boolean remove(Object key) {\r
61             throw new UnsupportedOperationException(IMMUTABLE_MSG);\r
62         }\r
63         public boolean remove(Object key, Object value) {\r
64             throw new UnsupportedOperationException(IMMUTABLE_MSG);\r
65         }\r
66     };\r
67 \r
68     @SuppressWarnings("unchecked")\r
69     public static <L, R> MapList<L, R> emptyMapList() {\r
70         return EMPTY_MAPLIST;\r
71     }\r
72 \r
73     protected Map<L, List<R>> lists;\r
74 \r
75     public MapList() {\r
76         lists = new THashMap<L, List<R>>();\r
77     }\r
78     \r
79     @SuppressWarnings("unchecked")\r
80         public MapList( Class<?> mapClass ) {\r
81         try {\r
82                         lists = (Map<L, List<R>>) mapClass.newInstance();\r
83                 } catch (InstantiationException e) {\r
84                         throw new RuntimeException( e );\r
85                 } catch (IllegalAccessException e) {\r
86                         throw new RuntimeException( e );\r
87                 }\r
88     }\r
89 \r
90     public MapList(MapList<L, R> copyFrom) {\r
91         for (Entry<L, List<R>> e : copyFrom.lists.entrySet())\r
92             lists.put( e.getKey(), new ArrayList<R>(e.getValue()) );\r
93     }\r
94 \r
95         public static <L, R> MapList<L, R> use( Map<L, List<R>> map ) {\r
96                 MapList<L, R> result = new MapList<L, R>();\r
97                 result.lists = map;\r
98                 return result;\r
99         }\r
100     \r
101     public void add(L key) {\r
102         getOrCreateList(key);\r
103     }\r
104 \r
105     public void add(L key, R value)\r
106     {\r
107         List<R> list = getOrCreateList(key);\r
108         list.add(value);\r
109     }\r
110 \r
111     public void add(L key, int index, R value)\r
112     {\r
113         ArrayList<R> list = getOrCreateList(key);\r
114         list.add(index, value);\r
115     }\r
116 \r
117         public void addAll(L key, Collection<R> values) {\r
118                 ArrayList<R> list = getOrCreateList(key);\r
119                 list.addAll(values);\r
120         }\r
121     \r
122     private ArrayList<R> getOrCreateList(L key)\r
123     {\r
124         ArrayList<R> list = (ArrayList<R>) lists.get(key);\r
125         if (list==null) {\r
126             list = new ArrayList<R>(1);\r
127             lists.put(key, list);\r
128         }\r
129         return list;\r
130     }\r
131 \r
132     private List<R> getList(L key)\r
133     {\r
134         return lists.get(key);\r
135     }\r
136 \r
137     public boolean remove(L key, R value)\r
138     {\r
139         List<R> list = getList(key);\r
140         if (list==null) return false;\r
141         boolean result = list.remove(value);\r
142         if (list.size()==0)\r
143             lists.remove(key);\r
144         return result;\r
145     }\r
146 \r
147     public boolean remove(L key)\r
148     {\r
149         List<R> list = getList(key);\r
150         if (list==null) return false;\r
151         lists.remove(key);\r
152         return true;\r
153     }\r
154 \r
155     public void clear()\r
156     {\r
157         lists.clear();\r
158     }\r
159 \r
160     public L[] getKeys(L[] list)\r
161     {\r
162         return lists.keySet().toArray(list);\r
163     }\r
164 \r
165     public Set<L> getKeys()\r
166     {\r
167         return lists.keySet();\r
168     }\r
169 \r
170     public int getKeySize() {\r
171         return lists.size();\r
172     }\r
173 \r
174     public boolean containsKey(L key)\r
175     {\r
176         return lists.containsKey(key);\r
177     }\r
178 \r
179     public boolean contains(L key, R obj)\r
180     {\r
181         List<R> l = lists.get(key);\r
182         if (l==null) return false;\r
183         return l.contains(obj);\r
184 \r
185     }\r
186 \r
187     public R[] getValues(L key, R[] list)\r
188     {\r
189         List<R> l = lists.get(key);\r
190         if (l==null) return null;\r
191         return l.toArray(list);\r
192     }\r
193 \r
194     /**\r
195      * @param key\r
196      *            the key to get values for\r
197      * @param list\r
198      *            the list to fill with existing values for specified key. Fills\r
199      *            this array with at maximum as many values as there is room for\r
200      *            in the array even if there are more values available in the\r
201      *            maplist for the specified key.\r
202      * @return the amount of values existing for the key. May be smaller or\r
203      *         larger than the size of the provided list. If smaller, only the\r
204      *         first array indexes will be filled with data and if larger, all\r
205      *         array indexes will be filled with data.\r
206      */\r
207     public int getAtMostValues(L key, R[] list)\r
208     {\r
209         List<R> l = lists.get(key);\r
210         if (l==null) return 0;\r
211         int valueCount = l.size();\r
212         int size = Math.min(valueCount, list.length);\r
213         for (int i = 0; i < size; ++i)\r
214             list[i] = l.get(i);\r
215         return valueCount;\r
216     }\r
217 \r
218     /**\r
219      * Returns a the internal list values for the specified key. The list is\r
220      * valid as long as it contains elements. The list should not be modified\r
221      * but the return value of this method does not enforce it like\r
222      * {@link #getValues(Object)} does. Use this method when you know you will\r
223      * not risk a 3rd party modifying the returned list and you want to avoid\r
224      * the cost of extra memory allocation through\r
225      * {@link Collections#unmodifiableList(List)}.\r
226      * \r
227      * @param key\r
228      *            the key to look values for\r
229      * @return empty unmodifiable list if there is no list with the specified\r
230      *         key, otherwise an unmodifiable version of the stored list\r
231      */\r
232     public List<R> getValuesUnsafe(L key)\r
233     {\r
234         List<R> l = lists.get(key);\r
235         return l != null ? l : Collections.<R>emptyList();\r
236     }\r
237 \r
238     /**\r
239      * Returns a read-only reference to the values. The list is valid as long as\r
240      * it contains elements.\r
241      * \r
242      * @param key\r
243      * @return empty unmodifiable list if there is no list with the specified key,\r
244      *         otherwise an unmodifiable version of the stored list\r
245      */\r
246     public List<R> getValues(L key)\r
247     {\r
248         List<R> l = lists.get(key);\r
249         if (l==null) return Collections.emptyList();\r
250         return Collections.unmodifiableList(l);\r
251     }\r
252 \r
253     /**\r
254      * Returns a copy of the values\r
255      * \r
256      * @param key\r
257      * @return empty unmodifiable list if there is no list with the specified key,\r
258      *         otherwise a copy of the stored list\r
259      */\r
260     public List<R> getValuesSnapshot(L key)\r
261     {\r
262         List<R> l = lists.get(key);\r
263         if (l==null) return Collections.emptyList();\r
264         return new ArrayList<R>(l);\r
265     }\r
266     \r
267     public List<R> getAllValuesSnapshot() \r
268     {\r
269         return getAllValuesSnapshot(null);\r
270     }\r
271 \r
272     public List<R> getAllValuesSnapshot(List<R> result) \r
273     {\r
274         if (result == null)\r
275             result = new ArrayList<R>();\r
276         for (List<R> right : lists.values()) {\r
277             result.addAll(right);\r
278         }\r
279         return result;\r
280     }\r
281 \r
282     public boolean isEmpty() {\r
283         return lists.isEmpty();\r
284     }\r
285 \r
286     /**\r
287      * Makes _this_ maplist immutable.\r
288      */\r
289     public void makeImmutable() {\r
290         for (Entry<L, List<R>> e : lists.entrySet())\r
291             lists.put(e.getKey(), Collections.unmodifiableList(e.getValue()));\r
292         lists = Collections.unmodifiableMap(lists);\r
293     }\r
294 \r
295 }\r