/* * Copyright (c) 2012, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * SQL Power Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multimap; import com.google.common.collect.Multiset; import com.google.common.collect.SortedSetMultimap; /** * An implementation of a sorted set multimap that stores the keys in a hash map * for constant time look up and values in a tree set. * <p> * Note that the methods which are documented to allow editing the underlying * map directly are not correct for this implementation. If a method is called, * like asMap, to get access to the map no modifications will be allowed to the * map structure. The objects in the map can still be modified. */ public class HashTreeSetMultimap<K, V> implements SortedSetMultimap<K, V> { private final Map<K, TreeSet<V>> map = new HashMap<K, TreeSet<V>>(); private final Comparator<V> valueComparator; public HashTreeSetMultimap(Comparator<V> valueComparator) { this.valueComparator = valueComparator; } @Override public Set<Entry<K, V>> entries() { Set<Entry<K, V>> entries = new HashSet<Entry<K,V>>(); for (final K k : map.keySet()) { for (final V v : map.get(k)) { entries.add(new Entry<K, V>() { @Override public K getKey() { return k; } @Override public V getValue() { return v; } @Override public V setValue(V value) { throw new IllegalStateException(); } }); } } return entries; } @Override public void clear() { map.clear(); } @Override public boolean containsEntry(Object k, Object v) { return map.get(k).contains(v); } @Override public boolean containsKey(Object k) { return map.containsKey(k); } @Override public boolean containsValue(Object v) { for (Map.Entry<K, TreeSet<V>> entry : map.entrySet()) { if (entry.getValue().contains(v)) return true; } return false; } @Override public boolean isEmpty() { return map.isEmpty(); } @Override public Set<K> keySet() { return map.keySet(); } @Override public Multiset<K> keys() { return HashMultiset.create(map.keySet()); } @Override public boolean put(K k, V v) { TreeSet<V> set = map.get(k); if (set == null) { set = new TreeSet<V>(valueComparator); map.put(k, set); } return set.add(v); } @Override public boolean putAll(Multimap<? extends K, ? extends V> newValues) { for (Map.Entry<? extends K, ? extends V> entry : newValues.entries()) { put(entry.getKey(), entry.getValue()); } return false; } @Override public boolean putAll(K k, Iterable<? extends V> values) { boolean mapChanged = false; for (V v : values) { mapChanged = mapChanged || put(k, v); } return mapChanged; } @Override public boolean remove(Object k, Object v) { if (map.get(k) == null) return false; boolean removed = map.get(k).remove(v); if (map.get(k).isEmpty()) { map.remove(k); } return removed; } @Override public int size() { return values().size(); } @Override public Collection<V> values() { List<V> values = new ArrayList<V>(); for (K k : map.keySet()) { values.addAll(map.get(k)); } return null; } @Override public Map<K, Collection<V>> asMap() { return Collections.<K, Collection<V>>unmodifiableMap(map); } @Override public SortedSet<V> get(K k) { if (map.get(k) == null) return new TreeSet<V>(); return Collections.unmodifiableSortedSet(map.get(k)); } @Override public SortedSet<V> removeAll(Object k) { return map.remove(k); } @Override public SortedSet<V> replaceValues(K k, Iterable<? extends V> values) { SortedSet<V> replacedValues = new TreeSet<V>(); for (V v : values) { if (remove(k, v)) { replacedValues.add(v); } put(k, v); } return replacedValues; } @Override public Comparator<? super V> valueComparator() { return valueComparator; } }