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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
15 package org.simantics.utils.datastructures;
\r
17 import gnu.trove.map.hash.THashMap;
\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
28 * MapList is a data structure with map on left side and arraylist on right side.
\r
31 * @author Toni Kalajainen
\r
33 public class MapList<L, R> {
\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
40 public void add(Object key) {
\r
41 throw new UnsupportedOperationException(IMMUTABLE_MSG);
\r
44 public void add(Object key, int index, Object value) {
\r
45 throw new UnsupportedOperationException(IMMUTABLE_MSG);
\r
48 public void add(Object key, Object value) {
\r
49 throw new UnsupportedOperationException(IMMUTABLE_MSG);
\r
52 public void addAll(Object key, Collection values) {
\r
53 throw new UnsupportedOperationException(IMMUTABLE_MSG);
\r
56 public void clear() {
\r
57 throw new UnsupportedOperationException(IMMUTABLE_MSG);
\r
60 public boolean remove(Object key) {
\r
61 throw new UnsupportedOperationException(IMMUTABLE_MSG);
\r
63 public boolean remove(Object key, Object value) {
\r
64 throw new UnsupportedOperationException(IMMUTABLE_MSG);
\r
68 @SuppressWarnings("unchecked")
\r
69 public static <L, R> MapList<L, R> emptyMapList() {
\r
70 return EMPTY_MAPLIST;
\r
73 protected Map<L, List<R>> lists;
\r
76 lists = new THashMap<L, List<R>>();
\r
79 @SuppressWarnings("unchecked")
\r
80 public MapList( Class<?> mapClass ) {
\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
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
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
101 public void add(L key) {
\r
102 getOrCreateList(key);
\r
105 public void add(L key, R value)
\r
107 List<R> list = getOrCreateList(key);
\r
111 public void add(L key, int index, R value)
\r
113 ArrayList<R> list = getOrCreateList(key);
\r
114 list.add(index, value);
\r
117 public void addAll(L key, Collection<R> values) {
\r
118 ArrayList<R> list = getOrCreateList(key);
\r
119 list.addAll(values);
\r
122 private ArrayList<R> getOrCreateList(L key)
\r
124 ArrayList<R> list = (ArrayList<R>) lists.get(key);
\r
126 list = new ArrayList<R>(1);
\r
127 lists.put(key, list);
\r
132 private List<R> getList(L key)
\r
134 return lists.get(key);
\r
137 public boolean remove(L key, R value)
\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
147 public boolean remove(L key)
\r
149 List<R> list = getList(key);
\r
150 if (list==null) return false;
\r
155 public void clear()
\r
160 public L[] getKeys(L[] list)
\r
162 return lists.keySet().toArray(list);
\r
165 public Set<L> getKeys()
\r
167 return lists.keySet();
\r
170 public int getKeySize() {
\r
171 return lists.size();
\r
174 public boolean containsKey(L key)
\r
176 return lists.containsKey(key);
\r
179 public boolean contains(L key, R obj)
\r
181 List<R> l = lists.get(key);
\r
182 if (l==null) return false;
\r
183 return l.contains(obj);
\r
187 public R[] getValues(L key, R[] list)
\r
189 List<R> l = lists.get(key);
\r
190 if (l==null) return null;
\r
191 return l.toArray(list);
\r
196 * the key to get values for
\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
207 public int getAtMostValues(L key, R[] list)
\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
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
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
232 public List<R> getValuesUnsafe(L key)
\r
234 List<R> l = lists.get(key);
\r
235 return l != null ? l : Collections.<R>emptyList();
\r
239 * Returns a read-only reference to the values. The list is valid as long as
\r
240 * it contains elements.
\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
246 public List<R> getValues(L key)
\r
248 List<R> l = lists.get(key);
\r
249 if (l==null) return Collections.emptyList();
\r
250 return Collections.unmodifiableList(l);
\r
254 * Returns a copy of the values
\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
260 public List<R> getValuesSnapshot(L key)
\r
262 List<R> l = lists.get(key);
\r
263 if (l==null) return Collections.emptyList();
\r
264 return new ArrayList<R>(l);
\r
267 public List<R> getAllValuesSnapshot()
\r
269 return getAllValuesSnapshot(null);
\r
272 public List<R> getAllValuesSnapshot(List<R> result)
\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
282 public boolean isEmpty() {
\r
283 return lists.isEmpty();
\r
287 * Makes _this_ maplist immutable.
\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