blob: 109b38bf02a8f5ad671b367c8f95274227c7094d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2015 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.common.utility.internal.collection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.jpt.common.utility.factory.Factory;
import org.eclipse.jpt.common.utility.internal.ClassTools;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
import org.eclipse.jpt.common.utility.predicate.Predicate;
import org.eclipse.jpt.common.utility.transformer.Transformer;
/**
* {@link Map} utility methods.
*/
public final class MapTools {
// ********** get (with default value) **********
/**
* Return the value mapped by the specified map to the specified key.
* If the specified key is not mapped, map the key to the specified default
* value and return it.
* @see Map#get(Object)
* @see Map#containsKey(Object)
*/
public static <K, V> V get(Map<K, V> map, K key, V defaultValue) {
V value = map.get(key);
if ((value != null) || map.containsKey(key)) {
return value;
}
map.put(key, defaultValue);
return defaultValue;
}
/**
* <em>Assume</em> the map does not contain any <code>null</code> values.
* @see #get(Map, Object, Object)
*/
public static <K, V> V get_(Map<K, V> map, K key, V defaultValue) {
V value = map.get(key);
if (value != null) {
return value;
}
map.put(key, defaultValue);
return defaultValue;
}
/**
* Return the value mapped by the specified map to the specified key.
* If the specified key is not mapped, map the key to the value returned by
* the specified factory and return it.
* @see Map#get(Object)
* @see Map#containsKey(Object)
*/
public static <K, V> V get(Map<K, V> map, K key, Factory<? extends V> factory) {
V value = map.get(key);
if ((value != null) || map.containsKey(key)) {
return value;
}
V defaultValue = factory.create();
map.put(key, defaultValue);
return defaultValue;
}
/**
* <em>Assume</em> the map does not contain any <code>null</code> values.
* @see #get(Map, Object, Factory)
*/
public static <K, V> V get_(Map<K, V> map, K key, Factory<? extends V> factory) {
V value = map.get(key);
if (value != null) {
return value;
}
V defaultValue = factory.create();
map.put(key, defaultValue);
return defaultValue;
}
/**
* Return the value mapped by the specified map to the specified key.
* If the specified key is not mapped, map the key to a new instance of the
* specified class, using the class's zero-argument constructor, and return
* it.
* @see Map#get(Object)
* @see Map#containsKey(Object)
*/
public static <K, V, C extends V> V get(Map<K, V> map, K key, Class<C> clazz) {
return get(map, key, clazz, ClassTools.EMPTY_ARRAY, ObjectTools.EMPTY_OBJECT_ARRAY);
}
/**
* <em>Assume</em> the map does not contain any <code>null</code> values.
* @see #get(Map, Object, Class)
*/
public static <K, V, C extends V> V get_(Map<K, V> map, K key, Class<C> clazz) {
return get_(map, key, clazz, ClassTools.EMPTY_ARRAY, ObjectTools.EMPTY_OBJECT_ARRAY);
}
/**
* Return the value mapped by the specified map to the specified key.
* If the specified key is not mapped, map the key to a new instance of the
* specified class, using the class's specified single-argument constructor,
* and return it.
* @see Map#get(Object)
* @see Map#containsKey(Object)
*/
public static <K, V, C extends V> V get(Map<K, V> map, K key, Class<C> clazz, Class<?> parameterType, Object argument) {
return get(map, key, clazz, new Class[] {parameterType}, new Object[] {argument});
}
/**
* <em>Assume</em> the map does not contain any <code>null</code> values.
* @see #get(Map, Object, Class, Class, Object)
*/
public static <K, V, C extends V> V get_(Map<K, V> map, K key, Class<C> clazz, Class<?> parameterType, Object argument) {
return get_(map, key, clazz, new Class[] {parameterType}, new Object[] {argument});
}
/**
* Return the value mapped by the specified map to the specified key.
* If the specified key is not mapped, map the key to a new instance of the
* specified class, using the class's specified constructor, and return it.
* @see Map#get(Object)
* @see Map#containsKey(Object)
*/
public static <K, V> V get(Map<K, V> map, K key, Class<? extends V> clazz, Class<?>[] parameterTypes, Object[] arguments) {
V value = map.get(key);
if ((value != null) || map.containsKey(key)) {
return value;
}
V defaultValue = ClassTools.newInstance(clazz, parameterTypes, arguments);
map.put(key, defaultValue);
return defaultValue;
}
/**
* <em>Assume</em> the map does not contain any <code>null</code> values.
* @see #get(Map, Object, Class, Class[], Object[])
*/
public static <K, V> V get_(Map<K, V> map, K key, Class<? extends V> clazz, Class<?>[] parameterTypes, Object[] arguments) {
V value = map.get(key);
if (value != null) {
return value;
}
V defaultValue = ClassTools.newInstance(clazz, parameterTypes, arguments);
map.put(key, defaultValue);
return defaultValue;
}
// ********** add **********
/**
* With the specified map, map the specified value to the key generated by
* passing the value to the specified key transformer.
* Return the previous value associated with generated key.
* @see Map#put(Object, Object)
*/
public static <K, V, E extends V> V add(Map<K, V> map, E value, Transformer<? super E, ? extends K> keyTransformer) {
return map.put(keyTransformer.transform(value), value);
}
/**
* With the specified map, map the value generated by passing the specified
* element to the specified value transformer to the key generated by
* passing the value to the specified key transformer.
* Return the previous value associated with generated key.
* @see Map#put(Object, Object)
*/
public static <K, V, E> V add(Map<K, V> map, E element, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
return map.put(keyTransformer.transform(element), valueTransformer.transform(element));
}
// ********** add all **********
/**
* With the specified map, map the specified values to the keys generated by
* passing the values to the specified key transformer.
* @see Map#putAll(Map)
*/
public static <K, V, E extends V> void addAll(Map<K, V> map, Iterable<E> values, Transformer<? super E, ? extends K> keyTransformer) {
addAll(map, values.iterator(), keyTransformer);
}
/**
* With the specified map, map the specified values to the keys generated by
* passing the values to the specified key transformer.
* @see Map#putAll(Map)
*/
public static <K, V, E extends V> void addAll(Map<K, V> map, Iterator<E> values, Transformer<? super E, ? extends K> keyTransformer) {
while (values.hasNext()) {
add(map, values.next(), keyTransformer);
}
}
/**
* With the specified map, map the specified values to the keys generated by
* passing the values to the specified key transformer.
* @see Map#putAll(Map)
*/
public static <K, V, E extends V> void addAll(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, E... values) {
for (E value : values) {
add(map, value, keyTransformer);
}
}
/**
* With the specified map, map the values generated by passing the specified
* elements to the specified value transformer to the key generated by
* passing the elements to the specified key transformer.
* @see Map#putAll(Map)
*/
public static <K, V, E> void addAll(Map<K, V> map, Iterable<E> elements, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
addAll(map, elements.iterator(), keyTransformer, valueTransformer);
}
/**
* With the specified map, map the values generated by passing the specified
* elements to the specified value transformer to the key generated by
* passing the elements to the specified key transformer.
* @see Map#putAll(Map)
*/
public static <K, V, E> void addAll(Map<K, V> map, Iterator<E> elements, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
while (elements.hasNext()) {
add(map, elements.next(), keyTransformer, valueTransformer);
}
}
/**
* With the specified map, map the values generated by passing the specified
* elements to the specified value transformer to the key generated by
* passing the elements to the specified key transformer.
* @see Map#putAll(Map)
*/
public static <K, V, E> void addAll(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer, E... elements) {
for (E element : elements) {
add(map, element, keyTransformer, valueTransformer);
}
}
// ********** put all **********
/**
* Map the specified keys and values in the specified map.
* The two lists must be the same size. The keys are matched up with
* the values by index. If there are duplicate keys, the last value in the
* list for a particular key will be the resulting value.
* @see Map#putAll(Map)
*/
public static <K, V> void putAll(Map<K, V> map, List<? extends K> keys, List<? extends V> values) {
if (keys.size() != values.size()) {
throw new IllegalArgumentException("unequal sizes - keys: " + keys.size() + " values: " + values.size()); //$NON-NLS-1$ //$NON-NLS-2$
}
for (int i = 0; i < keys.size(); i++) {
map.put(keys.get(i), values.get(i));
}
}
/**
* Map the specified keys and values in the specified map.
* The two arrays must be the same size. The keys are matched up with
* the values by index. If there are duplicate keys, the last value in the
* array for a particular key will be the resulting value.
* @see Map#putAll(Map)
*/
public static <K, V> void putAll(Map<K, V> map, K[] keys, V[] values) {
if (keys.length != values.length) {
throw new IllegalArgumentException("unequal lengths - keys: " + keys.length + " values: " + values.length); //$NON-NLS-1$ //$NON-NLS-2$
}
for (int i = 0; i < keys.length; i++) {
map.put(keys[i], values[i]);
}
}
// ********** contains all keys **********
/**
* Return whether the specified map contains all of the
* keys in the specified iterable.
* @see Map#containsKey(Object)
*/
public static boolean containsAllKeys(Map<?, ?> map, Iterable<?> keys) {
return containsAllKeys(map, keys.iterator());
}
/**
* Return whether the specified map contains all of the
* keys in the specified iterable, retrieving elements from the iterator
* until one is not found in the map.
* @see Map#containsKey(Object)
*/
public static boolean containsAllKeys(Map<?, ?> map, Iterator<?> keys) {
while (keys.hasNext()) {
if ( ! map.containsKey(keys.next())) {
return false;
}
}
return true;
}
/**
* Return whether the specified map contains all of the
* keys in the specified array.
* @see Map#containsKey(Object)
*/
public static boolean containsAllKeys(Map<?, ?> map, Object... keys) {
for (int i = keys.length; i-- > 0; ) {
if ( ! map.containsKey(keys[i])) {
return false;
}
}
return true;
}
// ********** contains all values **********
/**
* Return whether the specified map contains all of the
* values in the specified iterable.
* @see Map#containsValue(Object)
*/
public static boolean containsAllValues(Map<?, ?> map, Iterable<?> values) {
return containsAllValues(map, values.iterator());
}
/**
* Return whether the specified map contains all of the
* values in the specified iterable, retrieving elements from the iterator
* until one is not found in the map.
* @see Map#containsValue(Object)
*/
public static boolean containsAllValues(Map<?, ?> map, Iterator<?> values) {
while (values.hasNext()) {
if ( ! map.containsValue(values.next())) {
return false;
}
}
return true;
}
/**
* Return whether the specified map contains all of the
* values in the specified array.
* @see Map#containsValue(Object)
*/
public static boolean containsAllValues(Map<?, ?> map, Object... values) {
for (int i = values.length; i-- > 0; ) {
if ( ! map.containsValue(values[i])) {
return false;
}
}
return true;
}
// ********** remove all **********
/**
* Remove from the specified map all of the
* keys in the specified iterable.
* @see Map#remove(Object)
*/
public static void removeAll(Map<?, ?> map, Iterable<?> keys) {
removeAll(map, keys.iterator());
}
/**
* Remove from the specified map all of the
* keys returned by the specified iterator.
* @see Map#remove(Object)
*/
public static void removeAll(Map<?, ?> map, Iterator<?> keys) {
while (keys.hasNext()) {
map.remove(keys.next());
}
}
/**
* Remove from the specified map all of the
* keys returned by the specified array.
* @see Map#remove(Object)
*/
public static void removeAll(Map<?, ?> map, Object... keys) {
for (int i = keys.length; i-- > 0; ) {
map.remove(keys[i]);
}
}
// ********** retain all **********
/**
* Retain in the specified map only the
* keys in the specified collection.
*/
public static void retainAll(Map<?, ?> map, Collection<?> keys) {
if (keys.isEmpty()) {
map.clear();
} else {
retainAll_(map, keys);
}
}
/**
* Retain in the specified map only the
* keys in the specified iterable.
*/
public static void retainAll(Map<?, ?> map, Iterable<?> keys) {
retainAll(map, keys.iterator());
}
/**
* Retain in the specified map only the
* keys in the specified iterable.
* The specified size is a performance hint.
*/
public static void retainAll(Map<?, ?> map, Iterable<?> keys, int keysSize) {
retainAll(map, keys.iterator(), keysSize);
}
/**
* Retain in the specified map only the
* keys in the specified iterable.
*/
public static void retainAll(Map<?, ?> map, Iterator<?> keys) {
if (keys.hasNext()) {
retainAll_(map, CollectionTools.hashSet(keys));
} else {
map.clear();
}
}
/**
* Retain in the specified map only the
* keys in the specified iterable.
* The specified size is a performance hint.
*/
public static void retainAll(Map<?, ?> map, Iterator<?> keys, int keysSize) {
if (keys.hasNext()) {
retainAll_(map, CollectionTools.hashSet(keys, keysSize));
} else {
map.clear();
}
}
/**
* Retain in the specified map only the
* keys in the specified array.
*/
public static void retainAll(Map<?, ?> map, Object... keys) {
if (keys.length > 0) {
retainAll_(map, CollectionTools.hashSet(keys));
} else {
map.clear();
}
}
/**
* no empty check
*/
private static void retainAll_(Map<?, ?> map, Collection<?> keys) {
for (Iterator<? extends Map.Entry<?, ?>> stream = map.entrySet().iterator(); stream.hasNext(); ) {
Map.Entry<?, ?> entry = stream.next();
if ( ! keys.contains(entry.getKey())) {
stream.remove();
}
}
}
// ********** invert **********
/**
* Return a new map that is an <em>inversion</em> of the specified map
* (i.e. the old map's keys and values are inverted in the new map).
* If the old map contains any duplicate values, only a single mapping
* will remain in the new map.
*/
public static <K, V> HashMap<K, V> invert(Map<? extends V, ? extends K> map) {
HashMap<K, V> result = new HashMap<K, V>((int) (map.size() / 0.75));
for (Map.Entry<? extends V, ? extends K> entry : map.entrySet()) {
result.put(entry.getValue(), entry.getKey());
}
return result;
}
// ********** filter **********
/**
* Return a new map with the filtered
* values of the specified map.
*/
public static <K, V> HashMap<K, V> filter(Map<? extends K, ? extends V> map, Predicate<? super V> filter) {
HashMap<K, V> result = new HashMap<K, V>((int) (map.size() / 0.75));
for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
V value = entry.getValue();
if (filter.evaluate(value)) {
result.put(entry.getKey(), value);
}
}
return result;
}
// ********** transform **********
/**
* Return a new map with transformations of the
* values of the specified map.
*/
public static <K, V1, V2> HashMap<K, V2> transform(Map<? extends K, V1> map, Transformer<? super V1, ? extends V2> transformer) {
HashMap<K, V2> result = new HashMap<K, V2>((int) (map.size() / 0.75));
for (Map.Entry<? extends K, ? extends V1> entry : map.entrySet()) {
result.put(entry.getKey(), transformer.transform(entry.getValue()));
}
return result;
}
// ********** constructor **********
/**
* Suppress default constructor, ensuring non-instantiability.
*/
private MapTools() {
super();
throw new UnsupportedOperationException();
}
}