1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
15 package org.simantics.utils.datastructures;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.List;
23 import java.util.Map.Entry;
27 * MapList is a data structure with map on left side and arraylist on right side.
30 * @author Toni Kalajainen
32 public class MapList<L, R> {
34 @SuppressWarnings("rawtypes")
35 public static final MapList EMPTY_MAPLIST = new MapList() {
36 private static final String IMMUTABLE_MSG = "Cannot modify immutable empty MapList";
39 public void add(Object key) {
40 throw new UnsupportedOperationException(IMMUTABLE_MSG);
43 public void add(Object key, int index, Object value) {
44 throw new UnsupportedOperationException(IMMUTABLE_MSG);
47 public void add(Object key, Object value) {
48 throw new UnsupportedOperationException(IMMUTABLE_MSG);
51 public void addAll(Object key, Collection values) {
52 throw new UnsupportedOperationException(IMMUTABLE_MSG);
56 throw new UnsupportedOperationException(IMMUTABLE_MSG);
59 public boolean remove(Object key) {
60 throw new UnsupportedOperationException(IMMUTABLE_MSG);
62 public boolean remove(Object key, Object value) {
63 throw new UnsupportedOperationException(IMMUTABLE_MSG);
67 @SuppressWarnings("unchecked")
68 public static <L, R> MapList<L, R> emptyMapList() {
72 protected Map<L, List<R>> lists;
75 lists = new HashMap<L, List<R>>();
78 @SuppressWarnings("unchecked")
79 public MapList( Class<?> mapClass ) {
81 lists = (Map<L, List<R>>) mapClass.newInstance();
82 } catch (InstantiationException e) {
83 throw new RuntimeException( e );
84 } catch (IllegalAccessException e) {
85 throw new RuntimeException( e );
89 public MapList(MapList<L, R> copyFrom) {
90 for (Entry<L, List<R>> e : copyFrom.lists.entrySet())
91 lists.put( e.getKey(), new ArrayList<R>(e.getValue()) );
94 public static <L, R> MapList<L, R> use( Map<L, List<R>> map ) {
95 MapList<L, R> result = new MapList<L, R>();
100 public void add(L key) {
101 getOrCreateList(key);
104 public void add(L key, R value)
106 List<R> list = getOrCreateList(key);
110 public void add(L key, int index, R value)
112 ArrayList<R> list = getOrCreateList(key);
113 list.add(index, value);
116 public void addAll(L key, Collection<R> values) {
117 ArrayList<R> list = getOrCreateList(key);
121 private ArrayList<R> getOrCreateList(L key)
123 ArrayList<R> list = (ArrayList<R>) lists.get(key);
125 list = new ArrayList<R>(1);
126 lists.put(key, list);
131 private List<R> getList(L key)
133 return lists.get(key);
136 public boolean remove(L key, R value)
138 List<R> list = getList(key);
139 if (list==null) return false;
140 boolean result = list.remove(value);
146 public boolean remove(L key)
148 List<R> list = getList(key);
149 if (list==null) return false;
159 public L[] getKeys(L[] list)
161 return lists.keySet().toArray(list);
164 public Set<L> getKeys()
166 return lists.keySet();
169 public int getKeySize() {
173 public boolean containsKey(L key)
175 return lists.containsKey(key);
178 public boolean contains(L key, R obj)
180 List<R> l = lists.get(key);
181 if (l==null) return false;
182 return l.contains(obj);
186 public R[] getValues(L key, R[] list)
188 List<R> l = lists.get(key);
189 if (l==null) return null;
190 return l.toArray(list);
195 * the key to get values for
197 * the list to fill with existing values for specified key. Fills
198 * this array with at maximum as many values as there is room for
199 * in the array even if there are more values available in the
200 * maplist for the specified key.
201 * @return the amount of values existing for the key. May be smaller or
202 * larger than the size of the provided list. If smaller, only the
203 * first array indexes will be filled with data and if larger, all
204 * array indexes will be filled with data.
206 public int getAtMostValues(L key, R[] list)
208 List<R> l = lists.get(key);
209 if (l==null) return 0;
210 int valueCount = l.size();
211 int size = Math.min(valueCount, list.length);
212 for (int i = 0; i < size; ++i)
218 * Returns a the internal list values for the specified key. The list is
219 * valid as long as it contains elements. The list should not be modified
220 * but the return value of this method does not enforce it like
221 * {@link #getValues(Object)} does. Use this method when you know you will
222 * not risk a 3rd party modifying the returned list and you want to avoid
223 * the cost of extra memory allocation through
224 * {@link Collections#unmodifiableList(List)}.
227 * the key to look values for
228 * @return empty unmodifiable list if there is no list with the specified
229 * key, otherwise an unmodifiable version of the stored list
231 public List<R> getValuesUnsafe(L key)
233 List<R> l = lists.get(key);
234 return l != null ? l : Collections.<R>emptyList();
238 * Returns a read-only reference to the values. The list is valid as long as
239 * it contains elements.
242 * @return empty unmodifiable list if there is no list with the specified key,
243 * otherwise an unmodifiable version of the stored list
245 public List<R> getValues(L key)
247 List<R> l = lists.get(key);
248 if (l==null) return Collections.emptyList();
249 return Collections.unmodifiableList(l);
253 * Returns a copy of the values
256 * @return empty unmodifiable list if there is no list with the specified key,
257 * otherwise a copy of the stored list
259 public List<R> getValuesSnapshot(L key)
261 List<R> l = lists.get(key);
262 if (l==null) return Collections.emptyList();
263 return new ArrayList<R>(l);
266 public List<R> getAllValuesSnapshot()
268 return getAllValuesSnapshot(null);
271 public List<R> getAllValuesSnapshot(List<R> result)
274 result = new ArrayList<R>();
275 for (List<R> right : lists.values()) {
276 result.addAll(right);
281 public boolean isEmpty() {
282 return lists.isEmpty();
286 * Makes _this_ maplist immutable.
288 public void makeImmutable() {
289 for (Entry<L, List<R>> e : lists.entrySet())
290 lists.put(e.getKey(), Collections.unmodifiableList(e.getValue()));
291 lists = Collections.unmodifiableMap(lists);