/******************************************************************************* * Copyright (c) 2002 - 2006 IBM Corporation. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package com.ibm.wala.util.collections; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import com.ibm.wala.util.intset.MutableIntSet; import com.ibm.wala.util.intset.MutableSparseIntSet; /** * utilities for managing {@link Map}s */ public class MapUtil { /** * @param M a mapping from Object -> Set * @param key * @return the Set corresponding to key in M; create one if needed * @throws IllegalArgumentException if M is null * @throws ClassCastException if the key is of an inappropriate type for this map (optional) * @throws NullPointerException if the specified key is null and this map does not permit null keys (optional) */ public static <K, T> Set<T> findOrCreateSet(Map<K, Set<T>> M, K key) { if (M == null) { throw new IllegalArgumentException("M is null"); } Set<T> result = M.get(key); if (result == null) { result = HashSetFactory.make(2); M.put(key, result); } return result; } /** * @throws ClassCastException if the key is of an inappropriate type for this map (optional) * @throws NullPointerException if the specified key is null and this map does not permit null keys (optional) */ public static <K> MutableIntSet findOrCreateMutableIntSet(Map<K, MutableIntSet> M, K key) { if (M == null) { throw new IllegalArgumentException("M is null"); } MutableIntSet mis = M.get(key); if (mis == null) { mis = MutableSparseIntSet.makeEmpty(); M.put(key, mis); } return mis; } /** * @return the Collection corresponding to key in M; create one if needed * @throws ClassCastException if the key is of an inappropriate type for this map (optional) * @throws NullPointerException if the specified key is null and this map does not permit null keys (optional) */ public static <K, T> Collection<T> findOrCreateCollection(Map<K, Collection<T>> M, K key) { if (M == null) { throw new IllegalArgumentException("M is null"); } Collection<T> result = M.get(key); if (result == null) { result = HashSetFactory.make(2); M.put(key, result); } return result; } /** * @return the Set corresponding to key in M; create one if needed * @throws IllegalArgumentException if M is null * @throws ClassCastException if the key is of an inappropriate type for this map (optional) * @throws NullPointerException if the specified key is null and this map does not permit null keys (optional) */ public static <K, T> List<T> findOrCreateList(Map<K, List<T>> M, K key) { if (M == null) { throw new IllegalArgumentException("M is null"); } List<T> result = M.get(key); if (result == null) { result = new ArrayList<T>(); M.put(key, result); } return result; } /** * @param M a mapping from Object -> Map * @param key * @return the Map corresponding to key in M; create one if needed * @throws IllegalArgumentException if M is null * @throws ClassCastException if the key is of an inappropriate type for this map (optional) * @throws NullPointerException if the specified key is null and this map does not permit null keys (optional) */ public static <K, K2, V> Map<K2, V> findOrCreateMap(Map<K, Map<K2, V>> M, K key) { if (M == null) { throw new IllegalArgumentException("M is null"); } Map<K2, V> result = M.get(key); if (result == null) { result = HashMapFactory.make(2); M.put(key, result); } return result; } /** * @throws ClassCastException if the key is of an inappropriate type for this map (optional) * @throws NullPointerException if the specified key is null and this map does not permit null keys (optional) */ public static <K, V> V findOrCreateValue(Map<K, V> M, K key, Factory<V> factory) { if (M == null) { throw new IllegalArgumentException("M is null"); } V result = M.get(key); if (result == null) { result = factory.make(); M.put(key, result); } return result; } /** * @param M a mapping from Object -> WeakHashMap * @param key * @return the WeakHashMap corresponding to key in M; create one if needed * @throws IllegalArgumentException if M is null * @throws ClassCastException if the key is of an inappropriate type for this map (optional) * @throws NullPointerException if the specified key is null and this map does not permit null keys (optional) */ public static <K, V> WeakHashMap<K, V> findOrCreateWeakHashMap(Map<Object, WeakHashMap<K, V>> M, Object key) { if (M == null) { throw new IllegalArgumentException("M is null"); } WeakHashMap<K, V> result = M.get(key); if (result == null) { result = new WeakHashMap<K, V>(2); M.put(key, result); } return result; } /** * @param m a map from key -> Set <value> * @return inverted map, value -> Set <key> * @throws IllegalArgumentException if m is null */ public static <K, V> Map<V, Set<K>> inverseMap(Map<K, Set<V>> m) { if (m == null) { throw new IllegalArgumentException("m is null"); } Map<V, Set<K>> result = HashMapFactory.make(m.size()); for (Iterator<Map.Entry<K, Set<V>>> it = m.entrySet().iterator(); it.hasNext();) { Map.Entry<K, Set<V>> E = it.next(); K key = E.getKey(); Set<V> values = E.getValue(); for (Iterator<V> it2 = values.iterator(); it2.hasNext();) { V v = it2.next(); Set<K> s = findOrCreateSet(result, v); s.add(key); } } return result; } /** * invert an input map that is one-to-one (i.e., it does not map two different keys to the same value) * * @throws IllegalArgumentException if m is null * @throws IllegalArgumentException if m is not one-to-one */ public static <K, V> Map<V, K> invertOneToOneMap(Map<K, V> m) { if (m == null) { throw new IllegalArgumentException("m is null"); } Map<V, K> result = HashMapFactory.make(m.size()); for (Map.Entry<K, V> entry : m.entrySet()) { K key = entry.getKey(); V val = entry.getValue(); if (result.containsKey(val)) { throw new IllegalArgumentException("input map not one-to-one"); } result.put(val, key); } return result; } public static <K, V> Map<Set<K>, V> groupKeysByValue(Map<K, V> m) { if (m == null) { throw new IllegalArgumentException("m is null"); } Map<Set<K>, V> result = HashMapFactory.make(); Map<V, Set<K>> valueToKeys = HashMapFactory.make(); for (Iterator<Map.Entry<K, V>> it = m.entrySet().iterator(); it.hasNext();) { Map.Entry<K, V> E = it.next(); K key = E.getKey(); V value = E.getValue(); findOrCreateSet(valueToKeys, value).add(key); } for (Iterator<Map.Entry<V, Set<K>>> it = valueToKeys.entrySet().iterator(); it.hasNext();) { Map.Entry<V, Set<K>> E = it.next(); V value = E.getKey(); Set<K> keys = E.getValue(); result.put(keys, value); } return result; } }