blob: d4033f7fdf0dba566cece3eb01334e0b06c38c3c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.internal.serviceregistry;
import java.util.*;
public class ShrinkableValueCollectionMap<K, V> extends AbstractMap<K, Collection<V>> implements Map<K, Collection<V>> {
final Map<? extends K, ? extends Set<? extends Map.Entry<?, ? extends V>>> map;
Map<Object, Collection<V>> values;
public ShrinkableValueCollectionMap(Map<? extends K, ? extends Set<? extends Map.Entry<?, ? extends V>>> m) {
if (m == null) {
throw new NullPointerException();
}
map = m;
values = null;
}
public void clear() {
map.clear();
if (values != null) {
values.clear();
}
}
public boolean containsKey(Object key) {
return map.containsKey(key);
}
public boolean containsValue(Object value) {
/* Since values are collections and the collection has identity equality,
* there is no way any value could be contained in this map unless that
* value has already been gotten from this map.
*/
if (values == null) {
return false;
}
return values.containsValue(value);
}
public Set<Map.Entry<K, Collection<V>>> entrySet() {
return new EntrySet();
}
public Collection<V> get(Object key) {
Collection<V> value = null;
if (values != null) {
value = values.get(key);
}
if (value == null) {
Set<? extends Map.Entry<?, ? extends V>> entrySet = map.get(key);
if (entrySet == null) {
return null;
}
value = new ShrinkableEntrySetValueCollection<>(entrySet);
if (values == null) {
values = new HashMap<>(map.size());
}
values.put(key, value);
}
return value;
}
public boolean isEmpty() {
return map.isEmpty();
}
public Collection<V> remove(Object key) {
Set<? extends Map.Entry<?, ? extends V>> entrySet = map.remove(key);
Collection<V> value = null;
if (values != null) {
value = values.remove(key);
}
if ((value == null) && (entrySet != null)) {
value = new ShrinkableEntrySetValueCollection<>(entrySet);
}
return value;
}
public int size() {
return map.size();
}
/**
* Set class used for entry sets.
*/
private final class EntrySet extends AbstractSet<Map.Entry<K, Collection<V>>> {
EntrySet() {
super();
}
public Iterator<Map.Entry<K, Collection<V>>> iterator() {
return new EntryIterator();
}
public int size() {
return ShrinkableValueCollectionMap.this.size();
}
}
/**
* Iterator class used for entry sets.
*/
private final class EntryIterator implements Iterator<Map.Entry<K, Collection<V>>> {
private final Iterator<? extends K> iter;
private K last;
EntryIterator() {
iter = map.keySet().iterator();
}
public boolean hasNext() {
return iter.hasNext();
}
public Map.Entry<K, Collection<V>> next() {
last = iter.next();
return new Entry(last);
}
public void remove() {
iter.remove();
if (values != null) {
values.remove(last);
}
}
}
/**
* This class represents the entry in this map.
*/
private final class Entry implements Map.Entry<K, Collection<V>> {
private final K key;
private Collection<V> value;
Entry(final K k) {
key = k;
}
public K getKey() {
return key;
}
public Collection<V> getValue() {
if (value == null) {
value = ShrinkableValueCollectionMap.this.get(key);
}
return value;
}
public Collection<V> setValue(Collection<V> value) {
throw new UnsupportedOperationException(); // entries cannot be modified.
}
public String toString() {
return getKey() + "=" + getValue(); //$NON-NLS-1$
}
public int hashCode() {
return hash(getKey()) ^ hash(getValue());
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Map.Entry)) {
return false;
}
Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
return equality(getKey(), other.getKey()) && equality(getValue(), other.getValue());
}
}
static int hash(Object one) {
return (one == null) ? 0 : one.hashCode();
}
static boolean equality(Object one, Object two) {
return (one == null) ? (two == null) : one.equals(two);
}
}