org.glassfish.jersey.internal.guava.Maps Maven / Gradle / Ivy
Show all versions of jaxrs-ri Show documentation
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.glassfish.jersey.internal.guava;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.function.Function;
import java.util.function.Predicate;
import org.glassfish.jersey.internal.guava.Joiner.MapJoiner;
import static org.glassfish.jersey.internal.guava.Preconditions.checkArgument;
import static org.glassfish.jersey.internal.guava.Preconditions.checkNotNull;
import static org.glassfish.jersey.internal.guava.Predicates.compose;
/**
* Static utility methods pertaining to {@link Map} instances (including instances of
* {@link SortedMap}, {@link BiMap}, etc.). Also see this class's counterparts
* {@link Lists}, {@link Sets} and {@link Queues}.
*
*
See the Guava User Guide article on
* {@code Maps}.
*
* @author Kevin Bourrillion
* @author Mike Bostock
* @author Isaac Shum
* @author Louis Wasserman
* @since 2.0 (imported from Google Collections Library)
*/
public final class Maps {
private static final MapJoiner STANDARD_JOINER =
Collections2.STANDARD_JOINER.withKeyValueSeparator();
private Maps() {
}
@SuppressWarnings("unchecked")
private static Function, K> keyFunction() {
return (Function) EntryFunction.KEY;
}
@SuppressWarnings("unchecked")
private static Function, V> valueFunction() {
return (Function) EntryFunction.VALUE;
}
private static Iterator keyIterator(Iterator> entryIterator) {
return Iterators.transform(entryIterator, Maps.keyFunction());
}
static Iterator valueIterator(Iterator> entryIterator) {
return Iterators.transform(entryIterator, Maps.valueFunction());
}
/**
* Creates a {@code HashMap} instance, with a high enough "initial capacity"
* that it should hold {@code expectedSize} elements without growth.
* This behavior cannot be broadly guaranteed, but it is observed to be true
* for OpenJDK 1.6. It also can't be guaranteed that the method isn't
* inadvertently oversizing the returned map.
*
* @param expectedSize the number of elements you expect to add to the
* returned map
* @return a new, empty {@code HashMap} with enough capacity to hold {@code
* expectedSize} elements without resizing
* @throws IllegalArgumentException if {@code expectedSize} is negative
*/
public static HashMap newHashMapWithExpectedSize(
int expectedSize) {
return new HashMap(capacity(expectedSize));
}
/**
* Returns a capacity that is sufficient to keep the map from being resized as
* long as it grows no larger than expectedSize and the load factor is >= its
* default (0.75).
*/
static int capacity(int expectedSize) {
if (expectedSize < 3) {
CollectPreconditions.checkNonnegative(expectedSize, "expectedSize");
return expectedSize + 1;
}
if (expectedSize < Ints.MAX_POWER_OF_TWO) {
return expectedSize + expectedSize / 3;
}
return Integer.MAX_VALUE; // any large value
}
static Iterator> asMapEntryIterator(
Set set, final Function super K, V> function) {
return new TransformedIterator>(set.iterator()) {
@Override
Entry transform(final K key) {
return immutableEntry(key, function.apply(key));
}
};
}
private static Set removeOnlySet(final Set set) {
return new ForwardingSet() {
@Override
protected Set delegate() {
return set;
}
@Override
public boolean add(E element) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection extends E> es) {
throw new UnsupportedOperationException();
}
};
}
private static SortedSet removeOnlySortedSet(final SortedSet set) {
return new ForwardingSortedSet() {
@Override
protected SortedSet delegate() {
return set;
}
@Override
public boolean add(E element) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection extends E> es) {
throw new UnsupportedOperationException();
}
@Override
public SortedSet headSet(E toElement) {
return removeOnlySortedSet(super.headSet(toElement));
}
@Override
public SortedSet subSet(E fromElement, E toElement) {
return removeOnlySortedSet(super.subSet(fromElement, toElement));
}
@Override
public SortedSet tailSet(E fromElement) {
return removeOnlySortedSet(super.tailSet(fromElement));
}
};
}
/**
* Returns an immutable map entry with the specified key and value. The {@link
* Entry#setValue} operation throws an {@link UnsupportedOperationException}.
*
*
The returned entry is serializable.
*
* @param key the key to be associated with the returned entry
* @param value the value to be associated with the returned entry
*/
public static Entry immutableEntry(
K key, V value) {
return new ImmutableEntry(key, value);
}
static Predicate> keyPredicateOnEntries(Predicate super K> keyPredicate) {
return compose(keyPredicate, Maps.keyFunction());
}
static Predicate> valuePredicateOnEntries(Predicate super V> valuePredicate) {
return compose(valuePredicate, Maps.valueFunction());
}
/**
* Delegates to {@link Map#get}. Returns {@code null} on {@code
* ClassCastException} and {@code NullPointerException}.
*/
static V safeGet(Map, V> map, Object key) {
checkNotNull(map);
try {
return map.get(key);
} catch (ClassCastException e) {
return null;
} catch (NullPointerException e) {
return null;
}
}
/**
* Delegates to {@link Map#containsKey}. Returns {@code false} on {@code
* ClassCastException} and {@code NullPointerException}.
*/
static boolean safeContainsKey(Map, ?> map, Object key) {
checkNotNull(map);
try {
return map.containsKey(key);
} catch (ClassCastException e) {
return false;
} catch (NullPointerException e) {
return false;
}
}
/**
* Delegates to {@link Map#remove}. Returns {@code null} on {@code
* ClassCastException} and {@code NullPointerException}.
*/
static V safeRemove(Map, V> map, Object key) {
checkNotNull(map);
try {
return map.remove(key);
} catch (ClassCastException e) {
return null;
} catch (NullPointerException e) {
return null;
}
}
private enum EntryFunction implements Function, Object> {
KEY {
@Override
public Object apply(Entry, ?> entry) {
return entry.getKey();
}
},
VALUE {
@Override
public Object apply(Entry, ?> entry) {
return entry.getValue();
}
}
}
private static class AsMapView extends ImprovedAbstractMap {
final Function super K, V> function;
private final Set set;
AsMapView(Set set, Function super K, V> function) {
this.set = checkNotNull(set);
this.function = checkNotNull(function);
}
Set backingSet() {
return set;
}
@Override
public Set createKeySet() {
return removeOnlySet(backingSet());
}
@Override
Collection createValues() {
return Collections2.transform(set, function);
}
@Override
public int size() {
return backingSet().size();
}
@Override
public boolean containsKey(Object key) {
return backingSet().contains(key);
}
@Override
public V get(Object key) {
if (Collections2.safeContains(backingSet(), key)) {
@SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
K k = (K) key;
return function.apply(k);
} else {
return null;
}
}
@Override
public V remove(Object key) {
if (backingSet().remove(key)) {
@SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
K k = (K) key;
return function.apply(k);
} else {
return null;
}
}
@Override
public void clear() {
backingSet().clear();
}
@Override
protected Set> createEntrySet() {
return new EntrySet() {
@Override
Map map() {
return Maps.AsMapView.this;
}
@Override
public Iterator> iterator() {
return asMapEntryIterator(backingSet(), function);
}
};
}
}
/**
* {@code AbstractMap} extension that implements {@link #isEmpty()} as {@code
* entrySet().isEmpty()} instead of {@code size() == 0} to speed up
* implementations where {@code size()} is O(n), and it delegates the {@code
* isEmpty()} methods of its key set and value collection to this
* implementation.
*/
abstract static class ImprovedAbstractMap extends AbstractMap {
private transient Set> entrySet;
private transient Set keySet;
private transient Collection values;
/**
* Creates the entry set to be returned by {@link #entrySet()}. This method
* is invoked at most once on a given map, at the time when {@code entrySet}
* is first called.
*/
abstract Set> createEntrySet();
@Override
public Set> entrySet() {
Set> result = entrySet;
return (result == null) ? entrySet = createEntrySet() : result;
}
@Override
public Set keySet() {
Set result = keySet;
return (result == null) ? keySet = createKeySet() : result;
}
Set createKeySet() {
return new KeySet(this);
}
@Override
public Collection values() {
Collection result = values;
return (result == null) ? values = createValues() : result;
}
Collection createValues() {
return new Values(this);
}
}
static class KeySet extends Sets.ImprovedAbstractSet {
final Map map;
KeySet(Map map) {
this.map = checkNotNull(map);
}
Map map() {
return map;
}
@Override
public Iterator iterator() {
return keyIterator(map().entrySet().iterator());
}
@Override
public int size() {
return map().size();
}
@Override
public boolean isEmpty() {
return map().isEmpty();
}
@Override
public boolean contains(Object o) {
return map().containsKey(o);
}
@Override
public boolean remove(Object o) {
if (contains(o)) {
map().remove(o);
return true;
}
return false;
}
@Override
public void clear() {
map().clear();
}
}
static class Values extends AbstractCollection {
final Map map;
Values(Map map) {
this.map = checkNotNull(map);
}
final Map map() {
return map;
}
@Override
public Iterator iterator() {
return valueIterator(map().entrySet().iterator());
}
@Override
public boolean remove(Object o) {
try {
return super.remove(o);
} catch (UnsupportedOperationException e) {
for (Entry entry : map().entrySet()) {
if (Objects.equals(o, entry.getValue())) {
map().remove(entry.getKey());
return true;
}
}
return false;
}
}
@Override
public boolean removeAll(Collection> c) {
try {
return super.removeAll(checkNotNull(c));
} catch (UnsupportedOperationException e) {
Set toRemove = Sets.newHashSet();
for (Entry entry : map().entrySet()) {
if (c.contains(entry.getValue())) {
toRemove.add(entry.getKey());
}
}
return map().keySet().removeAll(toRemove);
}
}
@Override
public boolean retainAll(Collection> c) {
try {
return super.retainAll(checkNotNull(c));
} catch (UnsupportedOperationException e) {
Set toRetain = Sets.newHashSet();
for (Entry entry : map().entrySet()) {
if (c.contains(entry.getValue())) {
toRetain.add(entry.getKey());
}
}
return map().keySet().retainAll(toRetain);
}
}
@Override
public int size() {
return map().size();
}
@Override
public boolean isEmpty() {
return map().isEmpty();
}
@Override
public boolean contains(Object o) {
return map().containsValue(o);
}
@Override
public void clear() {
map().clear();
}
}
abstract static class EntrySet
extends Sets.ImprovedAbstractSet> {
abstract Map map();
@Override
public int size() {
return map().size();
}
@Override
public void clear() {
map().clear();
}
@Override
public boolean contains(Object o) {
if (o instanceof Entry) {
Entry, ?> entry = (Entry, ?>) o;
Object key = entry.getKey();
V value = Maps.safeGet(map(), key);
return Objects.equals(value, entry.getValue())
&& (value != null || map().containsKey(key));
}
return false;
}
@Override
public boolean isEmpty() {
return map().isEmpty();
}
@Override
public boolean remove(Object o) {
if (contains(o)) {
Entry, ?> entry = (Entry, ?>) o;
return map().keySet().remove(entry.getKey());
}
return false;
}
@Override
public boolean removeAll(Collection> c) {
try {
return super.removeAll(checkNotNull(c));
} catch (UnsupportedOperationException e) {
// if the iterators don't support remove
return Sets.removeAllImpl(this, c.iterator());
}
}
@Override
public boolean retainAll(Collection> c) {
try {
return super.retainAll(checkNotNull(c));
} catch (UnsupportedOperationException e) {
// if the iterators don't support remove
Set