]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/MapList.java
Utilize eclipse-collections immutable lists/map in datastructures
[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 java.util.Collection;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Map.Entry;
22 import java.util.Set;
23
24 import org.eclipse.collections.impl.factory.Lists;
25 import org.eclipse.collections.impl.factory.Maps;
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 = Maps.mutable.empty();
77     }
78
79     public MapList(MapList<L, R> copyFrom) {
80         for (Entry<L, List<R>> e : copyFrom.lists.entrySet())
81             lists.put( e.getKey(), Lists.mutable.withAll(e.getValue()) );
82     }
83
84         public static <L, R> MapList<L, R> use( Map<L, List<R>> map ) {
85                 MapList<L, R> result = new MapList<L, R>();
86                 result.lists = map;
87                 return result;
88         }
89     
90     public void add(L key) {
91         getOrCreateList(key);
92     }
93
94     public void add(L key, R value)
95     {
96         List<R> list = getOrCreateList(key);
97         list.add(value);
98     }
99
100     public void add(L key, int index, R value)
101     {
102         List<R> list = getOrCreateList(key);
103         list.add(index, value);
104     }
105
106         public void addAll(L key, Collection<R> values) {
107                 List<R> list = getOrCreateList(key);
108                 list.addAll(values);
109         }
110     
111     private List<R> getOrCreateList(L key)
112     {
113         List<R> list = lists.get(key);
114         if (list==null) {
115             list = Lists.mutable.withInitialCapacity(1);
116             lists.put(key, list);
117         }
118         return list;
119     }
120
121     private List<R> getList(L key)
122     {
123         return lists.get(key);
124     }
125
126     public boolean remove(L key, R value)
127     {
128         List<R> list = getList(key);
129         if (list==null) return false;
130         boolean result = list.remove(value);
131         if (list.size()==0)
132             lists.remove(key);
133         return result;
134     }
135
136     public boolean remove(L key)
137     {
138         List<R> list = getList(key);
139         if (list==null) return false;
140         lists.remove(key);
141         return true;
142     }
143
144     public void clear()
145     {
146         lists.clear();
147     }
148
149     public L[] getKeys(L[] list)
150     {
151         return lists.keySet().toArray(list);
152     }
153
154     public Set<L> getKeys()
155     {
156         return lists.keySet();
157     }
158
159     public int getKeySize() {
160         return lists.size();
161     }
162
163     public boolean containsKey(L key)
164     {
165         return lists.containsKey(key);
166     }
167
168     public boolean contains(L key, R obj)
169     {
170         List<R> l = lists.get(key);
171         if (l==null) return false;
172         return l.contains(obj);
173
174     }
175
176     public R[] getValues(L key, R[] list)
177     {
178         List<R> l = lists.get(key);
179         if (l==null) return null;
180         return l.toArray(list);
181     }
182
183     /**
184      * @param key
185      *            the key to get values for
186      * @param list
187      *            the list to fill with existing values for specified key. Fills
188      *            this array with at maximum as many values as there is room for
189      *            in the array even if there are more values available in the
190      *            maplist for the specified key.
191      * @return the amount of values existing for the key. May be smaller or
192      *         larger than the size of the provided list. If smaller, only the
193      *         first array indexes will be filled with data and if larger, all
194      *         array indexes will be filled with data.
195      */
196     public int getAtMostValues(L key, R[] list)
197     {
198         List<R> l = lists.get(key);
199         if (l==null) return 0;
200         int valueCount = l.size();
201         int size = Math.min(valueCount, list.length);
202         for (int i = 0; i < size; ++i)
203             list[i] = l.get(i);
204         return valueCount;
205     }
206
207     /**
208      * Returns a the internal list values for the specified key. The list is
209      * valid as long as it contains elements. The list should not be modified
210      * but the return value of this method does not enforce it like
211      * {@link #getValues(Object)} does. Use this method when you know you will
212      * not risk a 3rd party modifying the returned list and you want to avoid
213      * the cost of extra memory allocation through
214      * {@link Collections#unmodifiableList(List)}.
215      * 
216      * @param key
217      *            the key to look values for
218      * @return empty unmodifiable list if there is no list with the specified
219      *         key, otherwise an unmodifiable version of the stored list
220      */
221     public List<R> getValuesUnsafe(L key)
222     {
223         List<R> l = lists.get(key);
224         return l != null ? l : Collections.<R>emptyList();
225     }
226
227     /**
228      * Returns a read-only reference to the values. The list is valid as long as
229      * it contains elements.
230      * 
231      * @param key
232      * @return empty unmodifiable list if there is no list with the specified key,
233      *         otherwise an unmodifiable version of the stored list
234      */
235     public List<R> getValues(L key)
236     {
237         List<R> l = lists.get(key);
238         if (l==null) return Collections.emptyList();
239         return Collections.unmodifiableList(l);
240     }
241
242     /**
243      * Returns a copy of the values
244      * 
245      * @param key
246      * @return empty unmodifiable list if there is no list with the specified key,
247      *         otherwise a copy of the stored list
248      */
249     public List<R> getValuesSnapshot(L key)
250     {
251         List<R> l = lists.get(key);
252         if (l==null) return Collections.emptyList();
253         return Lists.mutable.withAll(l);
254     }
255     
256     public List<R> getAllValuesSnapshot() 
257     {
258         return getAllValuesSnapshot(null);
259     }
260
261     public List<R> getAllValuesSnapshot(List<R> result) 
262     {
263         if (result == null)
264             result = Lists.mutable.empty();
265         for (List<R> right : lists.values()) {
266             result.addAll(right);
267         }
268         return result;
269     }
270
271     public boolean isEmpty() {
272         return lists.isEmpty();
273     }
274
275     /**
276      * Makes _this_ maplist immutable.
277      */
278     @SuppressWarnings("unchecked")
279     public void makeImmutable() {
280         for (Entry<L, List<R>> e : lists.entrySet())
281             lists.put(e.getKey(), (List<R>) Lists.immutable.withAll(e.getValue()));
282         lists = (Map<L, List<R>>) Maps.immutable.withAll(lists);
283     }
284
285 }