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.Collection;
18 import java.util.Collections;
19 import java.util.List;
21 import java.util.Map.Entry;
24 import org.eclipse.collections.impl.factory.Lists;
25 import org.eclipse.collections.impl.factory.Maps;
28 * MapList is a data structure with map on left side and arraylist on right side.
31 * @author Toni Kalajainen
33 public class MapList<L, R> {
35 @SuppressWarnings("rawtypes")
36 public static final MapList EMPTY_MAPLIST = new MapList() {
37 private static final String IMMUTABLE_MSG = "Cannot modify immutable empty MapList";
40 public void add(Object key) {
41 throw new UnsupportedOperationException(IMMUTABLE_MSG);
44 public void add(Object key, int index, Object value) {
45 throw new UnsupportedOperationException(IMMUTABLE_MSG);
48 public void add(Object key, Object value) {
49 throw new UnsupportedOperationException(IMMUTABLE_MSG);
52 public void addAll(Object key, Collection values) {
53 throw new UnsupportedOperationException(IMMUTABLE_MSG);
57 throw new UnsupportedOperationException(IMMUTABLE_MSG);
60 public boolean remove(Object key) {
61 throw new UnsupportedOperationException(IMMUTABLE_MSG);
63 public boolean remove(Object key, Object value) {
64 throw new UnsupportedOperationException(IMMUTABLE_MSG);
68 @SuppressWarnings("unchecked")
69 public static <L, R> MapList<L, R> emptyMapList() {
73 protected Map<L, List<R>> lists;
76 lists = Maps.mutable.empty();
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()) );
84 public static <L, R> MapList<L, R> use( Map<L, List<R>> map ) {
85 MapList<L, R> result = new MapList<L, R>();
90 public void add(L key) {
94 public void add(L key, R value)
96 List<R> list = getOrCreateList(key);
100 public void add(L key, int index, R value)
102 List<R> list = getOrCreateList(key);
103 list.add(index, value);
106 public void addAll(L key, Collection<R> values) {
107 List<R> list = getOrCreateList(key);
111 private List<R> getOrCreateList(L key)
113 List<R> list = lists.get(key);
115 list = Lists.mutable.withInitialCapacity(1);
116 lists.put(key, list);
121 private List<R> getList(L key)
123 return lists.get(key);
126 public boolean remove(L key, R value)
128 List<R> list = getList(key);
129 if (list==null) return false;
130 boolean result = list.remove(value);
136 public boolean remove(L key)
138 List<R> list = getList(key);
139 if (list==null) return false;
149 public L[] getKeys(L[] list)
151 return lists.keySet().toArray(list);
154 public Set<L> getKeys()
156 return lists.keySet();
159 public int getKeySize() {
163 public boolean containsKey(L key)
165 return lists.containsKey(key);
168 public boolean contains(L key, R obj)
170 List<R> l = lists.get(key);
171 if (l==null) return false;
172 return l.contains(obj);
176 public R[] getValues(L key, R[] list)
178 List<R> l = lists.get(key);
179 if (l==null) return null;
180 return l.toArray(list);
185 * the key to get values for
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.
196 public int getAtMostValues(L key, R[] list)
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)
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)}.
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
221 public List<R> getValuesUnsafe(L key)
223 List<R> l = lists.get(key);
224 return l != null ? l : Collections.<R>emptyList();
228 * Returns a read-only reference to the values. The list is valid as long as
229 * it contains elements.
232 * @return empty unmodifiable list if there is no list with the specified key,
233 * otherwise an unmodifiable version of the stored list
235 public List<R> getValues(L key)
237 List<R> l = lists.get(key);
238 if (l==null) return Collections.emptyList();
239 return Collections.unmodifiableList(l);
243 * Returns a copy of the values
246 * @return empty unmodifiable list if there is no list with the specified key,
247 * otherwise a copy of the stored list
249 public List<R> getValuesSnapshot(L key)
251 List<R> l = lists.get(key);
252 if (l==null) return Collections.emptyList();
253 return Lists.mutable.withAll(l);
256 public List<R> getAllValuesSnapshot()
258 return getAllValuesSnapshot(null);
261 public List<R> getAllValuesSnapshot(List<R> result)
264 result = Lists.mutable.empty();
265 for (List<R> right : lists.values()) {
266 result.addAll(right);
271 public boolean isEmpty() {
272 return lists.isEmpty();
276 * Makes _this_ maplist immutable.
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);