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