All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.jersey.internal.guava.Maps Maven / Gradle / Ivy

There is a newer version: 4.0.0-M1
Show newest version
/*
 * 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 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 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 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 keyPredicate) { return compose(keyPredicate, Maps.keyFunction()); } static Predicate> valuePredicateOnEntries(Predicate valuePredicate) { return compose(valuePredicate, Maps.valueFunction()); } /** * Delegates to {@link Map#get}. Returns {@code null} on {@code * ClassCastException} and {@code NullPointerException}. */ static V safeGet(Map 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 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 function; private final Set set; AsMapView(Set set, Function 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 keys = Sets.newHashSetWithExpectedSize(c.size()); for (Object o : c) { if (contains(o)) { Entry entry = (Entry) o; keys.add(entry.getKey()); } } return map().keySet().retainAll(keys); } } } }