mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 02:48:14 -05:00
Update #0 - First Release
This commit is contained in:
441
sources/main/java/com/google/common/collect/AbstractBiMap.java
Normal file
441
sources/main/java/com/google/common/collect/AbstractBiMap.java
Normal file
@ -0,0 +1,441 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.CollectPreconditions.checkRemove;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* A general-purpose bimap implementation using any two backing {@code Map}
|
||||
* instances.
|
||||
*
|
||||
* <p>
|
||||
* Note that this class contains {@code equals()} calls that keep it from
|
||||
* supporting {@code IdentityHashMap} backing maps.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Mike Bostock
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V> implements BiMap<K, V>, Serializable {
|
||||
|
||||
private transient Map<K, V> delegate;
|
||||
transient AbstractBiMap<V, K> inverse;
|
||||
|
||||
/** Package-private constructor for creating a map-backed bimap. */
|
||||
AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
|
||||
setDelegates(forward, backward);
|
||||
}
|
||||
|
||||
/** Private constructor for inverse bimap. */
|
||||
private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) {
|
||||
delegate = backward;
|
||||
inverse = forward;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<K, V> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns its input, or throws an exception if this is not a valid key.
|
||||
*/
|
||||
K checkKey(@Nullable K key) {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns its input, or throws an exception if this is not a valid value.
|
||||
*/
|
||||
V checkValue(@Nullable V value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the delegate maps going in each direction. Called by the
|
||||
* constructor and by subclasses during deserialization.
|
||||
*/
|
||||
void setDelegates(Map<K, V> forward, Map<V, K> backward) {
|
||||
checkState(delegate == null);
|
||||
checkState(inverse == null);
|
||||
checkArgument(forward.isEmpty());
|
||||
checkArgument(backward.isEmpty());
|
||||
checkArgument(forward != backward);
|
||||
delegate = forward;
|
||||
inverse = new Inverse<V, K>(backward, this);
|
||||
}
|
||||
|
||||
void setInverse(AbstractBiMap<V, K> inverse) {
|
||||
this.inverse = inverse;
|
||||
}
|
||||
|
||||
// Query Operations (optimizations)
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@Nullable Object value) {
|
||||
return inverse.containsKey(value);
|
||||
}
|
||||
|
||||
// Modification Operations
|
||||
|
||||
@Override
|
||||
public V put(@Nullable K key, @Nullable V value) {
|
||||
return putInBothMaps(key, value, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V forcePut(@Nullable K key, @Nullable V value) {
|
||||
return putInBothMaps(key, value, true);
|
||||
}
|
||||
|
||||
private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) {
|
||||
checkKey(key);
|
||||
checkValue(value);
|
||||
boolean containedKey = containsKey(key);
|
||||
if (containedKey && Objects.equal(value, get(key))) {
|
||||
return value;
|
||||
}
|
||||
if (force) {
|
||||
inverse().remove(value);
|
||||
} else {
|
||||
checkArgument(!containsValue(value), "value already present: %s", value);
|
||||
}
|
||||
V oldValue = delegate.put(key, value);
|
||||
updateInverseMap(key, containedKey, oldValue, value);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
private void updateInverseMap(K key, boolean containedKey, V oldValue, V newValue) {
|
||||
if (containedKey) {
|
||||
removeFromInverseMap(oldValue);
|
||||
}
|
||||
inverse.delegate.put(newValue, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(@Nullable Object key) {
|
||||
return containsKey(key) ? removeFromBothMaps(key) : null;
|
||||
}
|
||||
|
||||
private V removeFromBothMaps(Object key) {
|
||||
V oldValue = delegate.remove(key);
|
||||
removeFromInverseMap(oldValue);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
private void removeFromInverseMap(V oldValue) {
|
||||
inverse.delegate.remove(oldValue);
|
||||
}
|
||||
|
||||
// Bulk Operations
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> map) {
|
||||
for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
delegate.clear();
|
||||
inverse.delegate.clear();
|
||||
}
|
||||
|
||||
// Views
|
||||
|
||||
@Override
|
||||
public BiMap<V, K> inverse() {
|
||||
return inverse;
|
||||
}
|
||||
|
||||
private transient Set<K> keySet;
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
Set<K> result = keySet;
|
||||
return (result == null) ? keySet = new KeySet() : result;
|
||||
}
|
||||
|
||||
private class KeySet extends ForwardingSet<K> {
|
||||
@Override
|
||||
protected Set<K> delegate() {
|
||||
return delegate.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
AbstractBiMap.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object key) {
|
||||
if (!contains(key)) {
|
||||
return false;
|
||||
}
|
||||
removeFromBothMaps(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> keysToRemove) {
|
||||
return standardRemoveAll(keysToRemove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> keysToRetain) {
|
||||
return standardRetainAll(keysToRetain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<K> iterator() {
|
||||
return Maps.keyIterator(entrySet().iterator());
|
||||
}
|
||||
}
|
||||
|
||||
private transient Set<V> valueSet;
|
||||
|
||||
@Override
|
||||
public Set<V> values() {
|
||||
/*
|
||||
* We can almost reuse the inverse's keySet, except we have to fix the iteration
|
||||
* order so that it is consistent with the forward map.
|
||||
*/
|
||||
Set<V> result = valueSet;
|
||||
return (result == null) ? valueSet = new ValueSet() : result;
|
||||
}
|
||||
|
||||
private class ValueSet extends ForwardingSet<V> {
|
||||
final Set<V> valuesDelegate = inverse.keySet();
|
||||
|
||||
@Override
|
||||
protected Set<V> delegate() {
|
||||
return valuesDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return Maps.valueIterator(entrySet().iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return standardToArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return standardToArray(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return standardToString();
|
||||
}
|
||||
}
|
||||
|
||||
private transient Set<Entry<K, V>> entrySet;
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
Set<Entry<K, V>> result = entrySet;
|
||||
return (result == null) ? entrySet = new EntrySet() : result;
|
||||
}
|
||||
|
||||
private class EntrySet extends ForwardingSet<Entry<K, V>> {
|
||||
final Set<Entry<K, V>> esDelegate = delegate.entrySet();
|
||||
|
||||
@Override
|
||||
protected Set<Entry<K, V>> delegate() {
|
||||
return esDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
AbstractBiMap.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object object) {
|
||||
if (!esDelegate.contains(object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// safe because esDelgate.contains(object).
|
||||
Entry<?, ?> entry = (Entry<?, ?>) object;
|
||||
inverse.delegate.remove(entry.getValue());
|
||||
/*
|
||||
* Remove the mapping in inverse before removing from esDelegate because if
|
||||
* entry is part of esDelegate, entry might be invalidated after the mapping is
|
||||
* removed from esDelegate.
|
||||
*/
|
||||
esDelegate.remove(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
final Iterator<Entry<K, V>> iterator = esDelegate.iterator();
|
||||
return new Iterator<Entry<K, V>>() {
|
||||
Entry<K, V> entry;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> next() {
|
||||
entry = iterator.next();
|
||||
final Entry<K, V> finalEntry = entry;
|
||||
|
||||
return new ForwardingMapEntry<K, V>() {
|
||||
@Override
|
||||
protected Entry<K, V> delegate() {
|
||||
return finalEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
// Preconditions keep the map and inverse consistent.
|
||||
checkState(contains(this), "entry no longer in map");
|
||||
// similar to putInBothMaps, but set via entry
|
||||
if (Objects.equal(value, getValue())) {
|
||||
return value;
|
||||
}
|
||||
checkArgument(!containsValue(value), "value already present: %s", value);
|
||||
V oldValue = finalEntry.setValue(value);
|
||||
checkState(Objects.equal(value, get(getKey())), "entry no longer in map");
|
||||
updateInverseMap(getKey(), true, oldValue, value);
|
||||
return oldValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
checkRemove(entry != null);
|
||||
V value = entry.getValue();
|
||||
iterator.remove();
|
||||
removeFromInverseMap(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// See java.util.Collections.CheckedEntrySet for details on attacks.
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return standardToArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return standardToArray(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return Maps.containsEntryImpl(delegate(), o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return standardContainsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return standardRemoveAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return standardRetainAll(c);
|
||||
}
|
||||
}
|
||||
|
||||
/** The inverse of any other {@code AbstractBiMap} subclass. */
|
||||
private static class Inverse<K, V> extends AbstractBiMap<K, V> {
|
||||
private Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) {
|
||||
super(backward, forward);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialization stores the forward bimap, the inverse of this inverse.
|
||||
* Deserialization calls inverse() on the forward bimap and returns that
|
||||
* inverse.
|
||||
*
|
||||
* If a bimap and its inverse are serialized together, the deserialized
|
||||
* instances have inverse() methods that return the other.
|
||||
*/
|
||||
|
||||
@Override
|
||||
K checkKey(K key) {
|
||||
return inverse.checkValue(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
V checkValue(V value) {
|
||||
return inverse.checkKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData the forward bimap
|
||||
*/
|
||||
@GwtIncompatible("java.io.ObjectOuputStream")
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
stream.writeObject(inverse());
|
||||
}
|
||||
|
||||
@GwtIncompatible("java.io.ObjectInputStream")
|
||||
@SuppressWarnings("unchecked") // reading data stored by writeObject
|
||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
setInverse((AbstractBiMap<V, K>) stream.readObject());
|
||||
}
|
||||
|
||||
@GwtIncompatible("Not needed in the emulated source.")
|
||||
Object readResolve() {
|
||||
return inverse().inverse();
|
||||
}
|
||||
|
||||
@GwtIncompatible("Not needed in emulated source.")
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
@GwtIncompatible("Not needed in emulated source.")
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkPositionIndex;
|
||||
|
||||
import java.util.ListIterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* This class provides a skeletal implementation of the {@link ListIterator}
|
||||
* interface across a fixed number of elements that may be retrieved by
|
||||
* position. It does not support {@link #remove}, {@link #set}, or {@link #add}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class AbstractIndexedListIterator<E> extends UnmodifiableListIterator<E> {
|
||||
private final int size;
|
||||
private int position;
|
||||
|
||||
/**
|
||||
* Returns the element with the specified index. This method is called by
|
||||
* {@link #next()}.
|
||||
*/
|
||||
protected abstract E get(int index);
|
||||
|
||||
/**
|
||||
* Constructs an iterator across a sequence of the given size whose initial
|
||||
* position is 0. That is, the first call to {@link #next()} will return the
|
||||
* first element (or throw {@link NoSuchElementException} if {@code size} is
|
||||
* zero).
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
protected AbstractIndexedListIterator(int size) {
|
||||
this(size, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an iterator across a sequence of the given size with the given
|
||||
* initial position. That is, the first call to {@link #nextIndex()} will return
|
||||
* {@code position}, and the first call to {@link #next()} will return the
|
||||
* element at that index, if available. Calls to {@link #previous()} can
|
||||
* retrieve the preceding {@code position} elements.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if {@code position} is negative or is
|
||||
* greater than {@code size}
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
protected AbstractIndexedListIterator(int size, int position) {
|
||||
checkPositionIndex(position, size);
|
||||
this.size = size;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasNext() {
|
||||
return position < size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final E next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return get(position++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int nextIndex() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasPrevious() {
|
||||
return position > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final E previous() {
|
||||
if (!hasPrevious()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return get(--position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int previousIndex() {
|
||||
return position - 1;
|
||||
}
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* This class provides a skeletal implementation of the {@code Iterator}
|
||||
* interface, to make this interface easier to implement for certain types of
|
||||
* data sources.
|
||||
*
|
||||
* <p>
|
||||
* {@code Iterator} requires its implementations to support querying the
|
||||
* end-of-data status without changing the iterator's state, using the
|
||||
* {@link #hasNext} method. But many data sources, such as
|
||||
* {@link java.io.Reader#read()}, do not expose this information; the only way
|
||||
* to discover whether there is any data left is by trying to retrieve it. These
|
||||
* types of data sources are ordinarily difficult to write iterators for. But
|
||||
* using this class, one must implement only the {@link #computeNext} method,
|
||||
* and invoke the {@link #endOfData} method when appropriate.
|
||||
*
|
||||
* <p>
|
||||
* Another example is an iterator that skips over null elements in a backing
|
||||
* iterator. This could be implemented as:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
*
|
||||
* public static Iterator<String> skipNulls(final Iterator<String> in) {
|
||||
* return new AbstractIterator<String>() {
|
||||
* protected String computeNext() {
|
||||
* while (in.hasNext()) {
|
||||
* String s = in.next();
|
||||
* if (s != null) {
|
||||
* return s;
|
||||
* }
|
||||
* }
|
||||
* return endOfData();
|
||||
* }
|
||||
* };
|
||||
* }}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* This class supports iterators that include null elements.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
// When making changes to this class, please also update the copy at
|
||||
// com.google.common.base.AbstractIterator
|
||||
@GwtCompatible
|
||||
public abstract class AbstractIterator<T> extends UnmodifiableIterator<T> {
|
||||
private State state = State.NOT_READY;
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected AbstractIterator() {
|
||||
}
|
||||
|
||||
private enum State {
|
||||
/** We have computed the next element and haven't returned it yet. */
|
||||
READY,
|
||||
|
||||
/** We haven't yet computed or have already returned the element. */
|
||||
NOT_READY,
|
||||
|
||||
/** We have reached the end of the data and are finished. */
|
||||
DONE,
|
||||
|
||||
/** We've suffered an exception and are kaput. */
|
||||
FAILED,
|
||||
}
|
||||
|
||||
private T next;
|
||||
|
||||
/**
|
||||
* Returns the next element. <b>Note:</b> the implementation must call
|
||||
* {@link #endOfData()} when there are no elements left in the iteration.
|
||||
* Failure to do so could result in an infinite loop.
|
||||
*
|
||||
* <p>
|
||||
* The initial invocation of {@link #hasNext()} or {@link #next()} calls this
|
||||
* method, as does the first invocation of {@code hasNext} or {@code
|
||||
* next} following each successful call to {@code next}. Once the implementation
|
||||
* either invokes {@code endOfData} or throws an exception, {@code computeNext}
|
||||
* is guaranteed to never be called again.
|
||||
*
|
||||
* <p>
|
||||
* If this method throws an exception, it will propagate outward to the
|
||||
* {@code hasNext} or {@code next} invocation that invoked this method. Any
|
||||
* further attempts to use the iterator will result in an
|
||||
* {@link IllegalStateException}.
|
||||
*
|
||||
* <p>
|
||||
* The implementation of this method may not invoke the {@code hasNext},
|
||||
* {@code next}, or {@link #peek()} methods on this instance; if it does, an
|
||||
* {@code IllegalStateException} will result.
|
||||
*
|
||||
* @return the next element if there was one. If {@code endOfData} was called
|
||||
* during execution, the return value will be ignored.
|
||||
* @throws RuntimeException if any unrecoverable error happens. This exception
|
||||
* will propagate outward to the {@code hasNext()},
|
||||
* {@code next()}, or {@code peek()} invocation that
|
||||
* invoked this method. Any further attempts to use the
|
||||
* iterator will result in an
|
||||
* {@link IllegalStateException}.
|
||||
*/
|
||||
protected abstract T computeNext();
|
||||
|
||||
/**
|
||||
* Implementations of {@link #computeNext} <b>must</b> invoke this method when
|
||||
* there are no elements left in the iteration.
|
||||
*
|
||||
* @return {@code null}; a convenience so your {@code computeNext}
|
||||
* implementation can use the simple statement
|
||||
* {@code return endOfData();}
|
||||
*/
|
||||
protected final T endOfData() {
|
||||
state = State.DONE;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasNext() {
|
||||
checkState(state != State.FAILED);
|
||||
switch (state) {
|
||||
case DONE:
|
||||
return false;
|
||||
case READY:
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
return tryToComputeNext();
|
||||
}
|
||||
|
||||
private boolean tryToComputeNext() {
|
||||
state = State.FAILED; // temporary pessimism
|
||||
next = computeNext();
|
||||
if (state != State.DONE) {
|
||||
state = State.READY;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
state = State.NOT_READY;
|
||||
T result = next;
|
||||
next = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration without advancing the iteration,
|
||||
* according to the contract of {@link PeekingIterator#peek()}.
|
||||
*
|
||||
* <p>
|
||||
* Implementations of {@code AbstractIterator} that wish to expose this
|
||||
* functionality should implement {@code PeekingIterator}.
|
||||
*/
|
||||
public final T peek() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return next;
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Basic implementation of the {@link ListMultimap} interface. It's a wrapper
|
||||
* around {@link AbstractMapBasedMultimap} that converts the returned
|
||||
* collections into {@code Lists}. The {@link #createCollection} method must
|
||||
* return a {@code
|
||||
* List}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class AbstractListMultimap<K, V> extends AbstractMapBasedMultimap<K, V> implements ListMultimap<K, V> {
|
||||
/**
|
||||
* Creates a new multimap that uses the provided map.
|
||||
*
|
||||
* @param map place to store the mapping from each key to its corresponding
|
||||
* values
|
||||
*/
|
||||
protected AbstractListMultimap(Map<K, Collection<V>> map) {
|
||||
super(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract List<V> createCollection();
|
||||
|
||||
@Override
|
||||
List<V> createUnmodifiableEmptyCollection() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
// Following Javadoc copied from ListMultimap.
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Because the values for a given key may have duplicates and follow the
|
||||
* insertion ordering, this method returns a {@link List}, instead of the
|
||||
* {@link Collection} specified in the {@link Multimap} interface.
|
||||
*/
|
||||
@Override
|
||||
public List<V> get(@Nullable K key) {
|
||||
return (List<V>) super.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Because the values for a given key may have duplicates and follow the
|
||||
* insertion ordering, this method returns a {@link List}, instead of the
|
||||
* {@link Collection} specified in the {@link Multimap} interface.
|
||||
*/
|
||||
@Override
|
||||
public List<V> removeAll(@Nullable Object key) {
|
||||
return (List<V>) super.removeAll(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Because the values for a given key may have duplicates and follow the
|
||||
* insertion ordering, this method returns a {@link List}, instead of the
|
||||
* {@link Collection} specified in the {@link Multimap} interface.
|
||||
*/
|
||||
@Override
|
||||
public List<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
|
||||
return (List<V>) super.replaceValues(key, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a key-value pair in the multimap.
|
||||
*
|
||||
* @param key key to store in the multimap
|
||||
* @param value value to store in the multimap
|
||||
* @return {@code true} always
|
||||
*/
|
||||
@Override
|
||||
public boolean put(@Nullable K key, @Nullable V value) {
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Though the method signature doesn't say so explicitly, the returned map has
|
||||
* {@link List} values.
|
||||
*/
|
||||
@Override
|
||||
public Map<K, Collection<V>> asMap() {
|
||||
return super.asMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the specified object to this multimap for equality.
|
||||
*
|
||||
* <p>
|
||||
* Two {@code ListMultimap} instances are equal if, for each key, they contain
|
||||
* the same values in the same order. If the value orderings disagree, the
|
||||
* multimaps will not be considered equal.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return super.equals(object);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 6588350623831699109L;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
|
||||
import static com.google.common.collect.CollectPreconditions.checkRemove;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
/**
|
||||
* Basic implementation of {@code Multiset<E>} backed by an instance of {@code
|
||||
* Map<E, Count>}.
|
||||
*
|
||||
* <p>
|
||||
* For serialization to work, the subclass must specify explicit {@code
|
||||
* readObject} and {@code writeObject} methods.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E> implements Serializable {
|
||||
|
||||
private transient Map<E, Count> backingMap;
|
||||
|
||||
/*
|
||||
* Cache the size for efficiency. Using a long lets us avoid the need for
|
||||
* overflow checking and ensures that size() will function correctly even if the
|
||||
* multiset had once been larger than Integer.MAX_VALUE.
|
||||
*/
|
||||
private transient long size;
|
||||
|
||||
/** Standard constructor. */
|
||||
protected AbstractMapBasedMultiset(Map<E, Count> backingMap) {
|
||||
this.backingMap = checkNotNull(backingMap);
|
||||
this.size = super.size();
|
||||
}
|
||||
|
||||
/** Used during deserialization only. The backing map must be empty. */
|
||||
void setBackingMap(Map<E, Count> backingMap) {
|
||||
this.backingMap = backingMap;
|
||||
}
|
||||
|
||||
// Required Implementations
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Invoking {@link Multiset.Entry#getCount} on an entry in the returned set
|
||||
* always returns the current count of that element in the multiset, as opposed
|
||||
* to the count at the time the entry was retrieved.
|
||||
*/
|
||||
@Override
|
||||
public Set<Multiset.Entry<E>> entrySet() {
|
||||
return super.entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
Iterator<Entry<E>> entryIterator() {
|
||||
final Iterator<Map.Entry<E, Count>> backingEntries = backingMap.entrySet().iterator();
|
||||
return new Iterator<Multiset.Entry<E>>() {
|
||||
Map.Entry<E, Count> toRemove;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return backingEntries.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multiset.Entry<E> next() {
|
||||
final Map.Entry<E, Count> mapEntry = backingEntries.next();
|
||||
toRemove = mapEntry;
|
||||
return new Multisets.AbstractEntry<E>() {
|
||||
@Override
|
||||
public E getElement() {
|
||||
return mapEntry.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
Count count = mapEntry.getValue();
|
||||
if (count == null || count.get() == 0) {
|
||||
Count frequency = backingMap.get(getElement());
|
||||
if (frequency != null) {
|
||||
return frequency.get();
|
||||
}
|
||||
}
|
||||
return (count == null) ? 0 : count.get();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
checkRemove(toRemove != null);
|
||||
size -= toRemove.getValue().getAndSet(0);
|
||||
backingEntries.remove();
|
||||
toRemove = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
for (Count frequency : backingMap.values()) {
|
||||
frequency.set(0);
|
||||
}
|
||||
backingMap.clear();
|
||||
size = 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
int distinctElements() {
|
||||
return backingMap.size();
|
||||
}
|
||||
|
||||
// Optimizations - Query Operations
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Ints.saturatedCast(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new MapBasedMultisetIterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* Not subclassing AbstractMultiset$MultisetIterator because next() needs to
|
||||
* retrieve the Map.Entry<E, Count> entry, which can then be used for a more
|
||||
* efficient remove() call.
|
||||
*/
|
||||
private class MapBasedMultisetIterator implements Iterator<E> {
|
||||
final Iterator<Map.Entry<E, Count>> entryIterator;
|
||||
Map.Entry<E, Count> currentEntry;
|
||||
int occurrencesLeft;
|
||||
boolean canRemove;
|
||||
|
||||
MapBasedMultisetIterator() {
|
||||
this.entryIterator = backingMap.entrySet().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return occurrencesLeft > 0 || entryIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
if (occurrencesLeft == 0) {
|
||||
currentEntry = entryIterator.next();
|
||||
occurrencesLeft = currentEntry.getValue().get();
|
||||
}
|
||||
occurrencesLeft--;
|
||||
canRemove = true;
|
||||
return currentEntry.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
checkRemove(canRemove);
|
||||
int frequency = currentEntry.getValue().get();
|
||||
if (frequency <= 0) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
if (currentEntry.getValue().addAndGet(-1) == 0) {
|
||||
entryIterator.remove();
|
||||
}
|
||||
size--;
|
||||
canRemove = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int count(@Nullable Object element) {
|
||||
Count frequency = Maps.safeGet(backingMap, element);
|
||||
return (frequency == null) ? 0 : frequency.get();
|
||||
}
|
||||
|
||||
// Optional Operations - Modification Operations
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws IllegalArgumentException if the call would result in more than
|
||||
* {@link Integer#MAX_VALUE} occurrences of
|
||||
* {@code element} in this multiset.
|
||||
*/
|
||||
@Override
|
||||
public int add(@Nullable E element, int occurrences) {
|
||||
if (occurrences == 0) {
|
||||
return count(element);
|
||||
}
|
||||
checkArgument(occurrences > 0, "occurrences cannot be negative: %s", occurrences);
|
||||
Count frequency = backingMap.get(element);
|
||||
int oldCount;
|
||||
if (frequency == null) {
|
||||
oldCount = 0;
|
||||
backingMap.put(element, new Count(occurrences));
|
||||
} else {
|
||||
oldCount = frequency.get();
|
||||
long newCount = (long) oldCount + (long) occurrences;
|
||||
checkArgument(newCount <= Integer.MAX_VALUE, "too many occurrences: %s", newCount);
|
||||
frequency.getAndAdd(occurrences);
|
||||
}
|
||||
size += occurrences;
|
||||
return oldCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remove(@Nullable Object element, int occurrences) {
|
||||
if (occurrences == 0) {
|
||||
return count(element);
|
||||
}
|
||||
checkArgument(occurrences > 0, "occurrences cannot be negative: %s", occurrences);
|
||||
Count frequency = backingMap.get(element);
|
||||
if (frequency == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oldCount = frequency.get();
|
||||
|
||||
int numberRemoved;
|
||||
if (oldCount > occurrences) {
|
||||
numberRemoved = occurrences;
|
||||
} else {
|
||||
numberRemoved = oldCount;
|
||||
backingMap.remove(element);
|
||||
}
|
||||
|
||||
frequency.addAndGet(-numberRemoved);
|
||||
size -= numberRemoved;
|
||||
return oldCount;
|
||||
}
|
||||
|
||||
// Roughly a 33% performance improvement over AbstractMultiset.setCount().
|
||||
@Override
|
||||
public int setCount(@Nullable E element, int count) {
|
||||
checkNonnegative(count, "count");
|
||||
|
||||
Count existingCounter;
|
||||
int oldCount;
|
||||
if (count == 0) {
|
||||
existingCounter = backingMap.remove(element);
|
||||
oldCount = getAndSet(existingCounter, count);
|
||||
} else {
|
||||
existingCounter = backingMap.get(element);
|
||||
oldCount = getAndSet(existingCounter, count);
|
||||
|
||||
if (existingCounter == null) {
|
||||
backingMap.put(element, new Count(count));
|
||||
}
|
||||
}
|
||||
|
||||
size += (count - oldCount);
|
||||
return oldCount;
|
||||
}
|
||||
|
||||
private static int getAndSet(Count i, int count) {
|
||||
if (i == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return i.getAndSet(count);
|
||||
}
|
||||
|
||||
// Don't allow default serialization.
|
||||
@GwtIncompatible("java.io.ObjectStreamException")
|
||||
@SuppressWarnings("unused") // actually used during deserialization
|
||||
private void readObjectNoData() throws ObjectStreamException {
|
||||
throw new InvalidObjectException("Stream data required");
|
||||
}
|
||||
|
||||
@GwtIncompatible("not needed in emulated source.")
|
||||
private static final long serialVersionUID = -2250766705698539974L;
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Implementation of the {@code equals}, {@code hashCode}, and {@code toString}
|
||||
* methods of {@code Entry}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class AbstractMapEntry<K, V> implements Entry<K, V> {
|
||||
|
||||
@Override
|
||||
public abstract K getKey();
|
||||
|
||||
@Override
|
||||
public abstract V getValue();
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
if (object instanceof Entry) {
|
||||
Entry<?, ?> that = (Entry<?, ?>) object;
|
||||
return Objects.equal(this.getKey(), that.getKey()) && Objects.equal(this.getValue(), that.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
K k = getKey();
|
||||
V v = getValue();
|
||||
return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the form {@code {key}={value}}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getKey() + "=" + getValue();
|
||||
}
|
||||
}
|
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A skeleton {@code Multimap} implementation, not necessarily in terms of a
|
||||
* {@code Map}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@Nullable Object value) {
|
||||
for (Collection<V> collection : asMap().values()) {
|
||||
if (collection.contains(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
|
||||
Collection<V> collection = asMap().get(key);
|
||||
return collection != null && collection.contains(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(@Nullable Object key, @Nullable Object value) {
|
||||
Collection<V> collection = asMap().get(key);
|
||||
return collection != null && collection.remove(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean put(@Nullable K key, @Nullable V value) {
|
||||
return get(key).add(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putAll(@Nullable K key, Iterable<? extends V> values) {
|
||||
checkNotNull(values);
|
||||
// make sure we only call values.iterator() once
|
||||
// and we only call get(key) if values is nonempty
|
||||
if (values instanceof Collection) {
|
||||
Collection<? extends V> valueCollection = (Collection<? extends V>) values;
|
||||
return !valueCollection.isEmpty() && get(key).addAll(valueCollection);
|
||||
} else {
|
||||
Iterator<? extends V> valueItr = values.iterator();
|
||||
return valueItr.hasNext() && Iterators.addAll(get(key), valueItr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
|
||||
boolean changed = false;
|
||||
for (Map.Entry<? extends K, ? extends V> entry : multimap.entries()) {
|
||||
changed |= put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
|
||||
checkNotNull(values);
|
||||
Collection<V> result = removeAll(key);
|
||||
putAll(key, values);
|
||||
return result;
|
||||
}
|
||||
|
||||
private transient Collection<Entry<K, V>> entries;
|
||||
|
||||
@Override
|
||||
public Collection<Entry<K, V>> entries() {
|
||||
Collection<Entry<K, V>> result = entries;
|
||||
return (result == null) ? entries = createEntries() : result;
|
||||
}
|
||||
|
||||
Collection<Entry<K, V>> createEntries() {
|
||||
if (this instanceof SetMultimap) {
|
||||
return new EntrySet();
|
||||
} else {
|
||||
return new Entries();
|
||||
}
|
||||
}
|
||||
|
||||
private class Entries extends Multimaps.Entries<K, V> {
|
||||
@Override
|
||||
Multimap<K, V> multimap() {
|
||||
return AbstractMultimap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
return entryIterator();
|
||||
}
|
||||
}
|
||||
|
||||
private class EntrySet extends Entries implements Set<Entry<K, V>> {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Sets.hashCodeImpl(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return Sets.equalsImpl(this, obj);
|
||||
}
|
||||
}
|
||||
|
||||
abstract Iterator<Entry<K, V>> entryIterator();
|
||||
|
||||
private transient Set<K> keySet;
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
Set<K> result = keySet;
|
||||
return (result == null) ? keySet = createKeySet() : result;
|
||||
}
|
||||
|
||||
Set<K> createKeySet() {
|
||||
return new Maps.KeySet<K, Collection<V>>(asMap());
|
||||
}
|
||||
|
||||
private transient Multiset<K> keys;
|
||||
|
||||
@Override
|
||||
public Multiset<K> keys() {
|
||||
Multiset<K> result = keys;
|
||||
return (result == null) ? keys = createKeys() : result;
|
||||
}
|
||||
|
||||
Multiset<K> createKeys() {
|
||||
return new Multimaps.Keys<K, V>(this);
|
||||
}
|
||||
|
||||
private transient Collection<V> values;
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
Collection<V> result = values;
|
||||
return (result == null) ? values = createValues() : result;
|
||||
}
|
||||
|
||||
Collection<V> createValues() {
|
||||
return new Values();
|
||||
}
|
||||
|
||||
class Values extends AbstractCollection<V> {
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return valueIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return AbstractMultimap.this.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object o) {
|
||||
return AbstractMultimap.this.containsValue(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
AbstractMultimap.this.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<V> valueIterator() {
|
||||
return Maps.valueIterator(entries().iterator());
|
||||
}
|
||||
|
||||
private transient Map<K, Collection<V>> asMap;
|
||||
|
||||
@Override
|
||||
public Map<K, Collection<V>> asMap() {
|
||||
Map<K, Collection<V>> result = asMap;
|
||||
return (result == null) ? asMap = createAsMap() : result;
|
||||
}
|
||||
|
||||
abstract Map<K, Collection<V>> createAsMap();
|
||||
|
||||
// Comparison and hashing
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return Multimaps.equalsImpl(this, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code for this multimap.
|
||||
*
|
||||
* <p>
|
||||
* The hash code of a multimap is defined as the hash code of the map view, as
|
||||
* returned by {@link Multimap#asMap}.
|
||||
*
|
||||
* @see Map#hashCode
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return asMap().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the multimap, generated by calling
|
||||
* {@code toString} on the map returned by {@link Multimap#asMap}.
|
||||
*
|
||||
* @return a string representation of the multimap
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return asMap().toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.collect.Multisets.setCountImpl;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* This class provides a skeletal implementation of the {@link Multiset}
|
||||
* interface. A new multiset implementation can be created easily by extending
|
||||
* this class and implementing the {@link Multiset#entrySet()} method, plus
|
||||
* optionally overriding {@link #add(Object, int)} and
|
||||
* {@link #remove(Object, int)} to enable modifications to the multiset.
|
||||
*
|
||||
* <p>
|
||||
* The {@link #count} and {@link #size} implementations all iterate across the
|
||||
* set returned by {@link Multiset#entrySet()}, as do many methods acting on the
|
||||
* set returned by {@link #elementSet()}. Override those methods for better
|
||||
* performance.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class AbstractMultiset<E> extends AbstractCollection<E> implements Multiset<E> {
|
||||
// Query Operations
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Multisets.sizeImpl(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return entrySet().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object element) {
|
||||
return count(element) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Multisets.iteratorImpl(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int count(@Nullable Object element) {
|
||||
for (Entry<E> entry : entrySet()) {
|
||||
if (Objects.equal(entry.getElement(), element)) {
|
||||
return entry.getCount();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Modification Operations
|
||||
|
||||
@Override
|
||||
public boolean add(@Nullable E element) {
|
||||
add(element, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int add(@Nullable E element, int occurrences) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(@Nullable Object element) {
|
||||
return remove(element, 1) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remove(@Nullable Object element, int occurrences) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setCount(@Nullable E element, int count) {
|
||||
return setCountImpl(this, element, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setCount(@Nullable E element, int oldCount, int newCount) {
|
||||
return setCountImpl(this, element, oldCount, newCount);
|
||||
}
|
||||
|
||||
// Bulk Operations
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* This implementation is highly efficient when {@code elementsToAdd} is itself
|
||||
* a {@link Multiset}.
|
||||
*/
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> elementsToAdd) {
|
||||
return Multisets.addAllImpl(this, elementsToAdd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> elementsToRemove) {
|
||||
return Multisets.removeAllImpl(this, elementsToRemove);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> elementsToRetain) {
|
||||
return Multisets.retainAllImpl(this, elementsToRetain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
Iterators.clear(entryIterator());
|
||||
}
|
||||
|
||||
// Views
|
||||
|
||||
private transient Set<E> elementSet;
|
||||
|
||||
@Override
|
||||
public Set<E> elementSet() {
|
||||
Set<E> result = elementSet;
|
||||
if (result == null) {
|
||||
elementSet = result = createElementSet();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this multiset's element set, which will be returned
|
||||
* by {@link #elementSet()}.
|
||||
*/
|
||||
Set<E> createElementSet() {
|
||||
return new ElementSet();
|
||||
}
|
||||
|
||||
class ElementSet extends Multisets.ElementSet<E> {
|
||||
@Override
|
||||
Multiset<E> multiset() {
|
||||
return AbstractMultiset.this;
|
||||
}
|
||||
}
|
||||
|
||||
abstract Iterator<Entry<E>> entryIterator();
|
||||
|
||||
abstract int distinctElements();
|
||||
|
||||
private transient Set<Entry<E>> entrySet;
|
||||
|
||||
@Override
|
||||
public Set<Entry<E>> entrySet() {
|
||||
Set<Entry<E>> result = entrySet;
|
||||
return (result == null) ? entrySet = createEntrySet() : result;
|
||||
}
|
||||
|
||||
class EntrySet extends Multisets.EntrySet<E> {
|
||||
@Override
|
||||
Multiset<E> multiset() {
|
||||
return AbstractMultiset.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<E>> iterator() {
|
||||
return entryIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return distinctElements();
|
||||
}
|
||||
}
|
||||
|
||||
Set<Entry<E>> createEntrySet() {
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
// Object methods
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* This implementation returns {@code true} if {@code object} is a multiset of
|
||||
* the same size and if, for each element, the two multisets have the same
|
||||
* count.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return Multisets.equalsImpl(this, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* This implementation returns the hash code of {@link Multiset#entrySet()}.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return entrySet().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* This implementation returns the result of invoking {@code toString} on
|
||||
* {@link Multiset#entrySet()}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return entrySet().toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Skeletal implementation of {@link NavigableMap}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
abstract class AbstractNavigableMap<K, V> extends AbstractMap<K, V> implements NavigableMap<K, V> {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public abstract V get(@Nullable Object key);
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entry<K, V> firstEntry() {
|
||||
return Iterators.getNext(entryIterator(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entry<K, V> lastEntry() {
|
||||
return Iterators.getNext(descendingEntryIterator(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entry<K, V> pollFirstEntry() {
|
||||
return Iterators.pollNext(entryIterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entry<K, V> pollLastEntry() {
|
||||
return Iterators.pollNext(descendingEntryIterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public K firstKey() {
|
||||
Entry<K, V> entry = firstEntry();
|
||||
if (entry == null) {
|
||||
throw new NoSuchElementException();
|
||||
} else {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public K lastKey() {
|
||||
Entry<K, V> entry = lastEntry();
|
||||
if (entry == null) {
|
||||
throw new NoSuchElementException();
|
||||
} else {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entry<K, V> lowerEntry(K key) {
|
||||
return headMap(key, false).lastEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entry<K, V> floorEntry(K key) {
|
||||
return headMap(key, true).lastEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entry<K, V> ceilingEntry(K key) {
|
||||
return tailMap(key, true).firstEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entry<K, V> higherEntry(K key) {
|
||||
return tailMap(key, false).firstEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K lowerKey(K key) {
|
||||
return Maps.keyOrNull(lowerEntry(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public K floorKey(K key) {
|
||||
return Maps.keyOrNull(floorEntry(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public K ceilingKey(K key) {
|
||||
return Maps.keyOrNull(ceilingEntry(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public K higherKey(K key) {
|
||||
return Maps.keyOrNull(higherEntry(key));
|
||||
}
|
||||
|
||||
abstract Iterator<Entry<K, V>> entryIterator();
|
||||
|
||||
abstract Iterator<Entry<K, V>> descendingEntryIterator();
|
||||
|
||||
@Override
|
||||
public SortedMap<K, V> subMap(K fromKey, K toKey) {
|
||||
return subMap(fromKey, true, toKey, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<K, V> headMap(K toKey) {
|
||||
return headMap(toKey, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<K, V> tailMap(K fromKey) {
|
||||
return tailMap(fromKey, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<K> navigableKeySet() {
|
||||
return new Maps.NavigableKeySet<K, V>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return navigableKeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract int size();
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return new Maps.EntrySet<K, V>() {
|
||||
@Override
|
||||
Map<K, V> map() {
|
||||
return AbstractNavigableMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
return entryIterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<K> descendingKeySet() {
|
||||
return descendingMap().navigableKeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableMap<K, V> descendingMap() {
|
||||
return new DescendingMap();
|
||||
}
|
||||
|
||||
private final class DescendingMap extends Maps.DescendingMap<K, V> {
|
||||
@Override
|
||||
NavigableMap<K, V> forward() {
|
||||
return AbstractNavigableMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
Iterator<Entry<K, V>> entryIterator() {
|
||||
return descendingEntryIterator();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A skeletal implementation of {@code RangeSet}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
abstract class AbstractRangeSet<C extends Comparable> implements RangeSet<C> {
|
||||
AbstractRangeSet() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(C value) {
|
||||
return rangeContaining(value) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Range<C> rangeContaining(C value);
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return asRanges().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Range<C> range) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Range<C> range) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
remove(Range.<C>all());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enclosesAll(RangeSet<C> other) {
|
||||
for (Range<C> range : other.asRanges()) {
|
||||
if (!encloses(range)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(RangeSet<C> other) {
|
||||
for (Range<C> range : other.asRanges()) {
|
||||
add(range);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll(RangeSet<C> other) {
|
||||
for (Range<C> range : other.asRanges()) {
|
||||
remove(range);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract boolean encloses(Range<C> otherRange);
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
} else if (obj instanceof RangeSet) {
|
||||
RangeSet<?> other = (RangeSet<?>) obj;
|
||||
return this.asRanges().equals(other.asRanges());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return asRanges().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return asRanges().toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 com.google.common.collect;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* This class provides a skeletal implementation of the {@code Iterator}
|
||||
* interface for sequences whose next element can always be derived from the
|
||||
* previous element. Null elements are not supported, nor is the
|
||||
* {@link #remove()} method.
|
||||
*
|
||||
* <p>
|
||||
* Example:
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* @code
|
||||
*
|
||||
* Iterator<Integer> powersOfTwo = new AbstractSequentialIterator<Integer>(1) {
|
||||
* protected Integer computeNext(Integer previous) {
|
||||
* return (previous == 1 << 30) ? null : previous * 2;
|
||||
* }
|
||||
* };
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Chris Povirk
|
||||
* @since 12.0 (in Guava as {@code AbstractLinkedIterator} since 8.0)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class AbstractSequentialIterator<T> extends UnmodifiableIterator<T> {
|
||||
private T nextOrNull;
|
||||
|
||||
/**
|
||||
* Creates a new iterator with the given first element, or, if {@code
|
||||
* firstOrNull} is null, creates a new empty iterator.
|
||||
*/
|
||||
protected AbstractSequentialIterator(@Nullable T firstOrNull) {
|
||||
this.nextOrNull = firstOrNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element that follows {@code previous}, or returns {@code null} if
|
||||
* no elements remain. This method is invoked during each call to
|
||||
* {@link #next()} in order to compute the result of a <i>future</i> call to
|
||||
* {@code next()}.
|
||||
*/
|
||||
protected abstract T computeNext(T previous);
|
||||
|
||||
@Override
|
||||
public final boolean hasNext() {
|
||||
return nextOrNull != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
try {
|
||||
return nextOrNull;
|
||||
} finally {
|
||||
nextOrNull = computeNext(nextOrNull);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Basic implementation of the {@link SetMultimap} interface. It's a wrapper
|
||||
* around {@link AbstractMapBasedMultimap} that converts the returned
|
||||
* collections into {@code Sets}. The {@link #createCollection} method must
|
||||
* return a {@code Set}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class AbstractSetMultimap<K, V> extends AbstractMapBasedMultimap<K, V> implements SetMultimap<K, V> {
|
||||
/**
|
||||
* Creates a new multimap that uses the provided map.
|
||||
*
|
||||
* @param map place to store the mapping from each key to its corresponding
|
||||
* values
|
||||
*/
|
||||
protected AbstractSetMultimap(Map<K, Collection<V>> map) {
|
||||
super(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract Set<V> createCollection();
|
||||
|
||||
@Override
|
||||
Set<V> createUnmodifiableEmptyCollection() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
// Following Javadoc copied from SetMultimap.
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Because a {@code SetMultimap} has unique values for a given key, this method
|
||||
* returns a {@link Set}, instead of the {@link Collection} specified in the
|
||||
* {@link Multimap} interface.
|
||||
*/
|
||||
@Override
|
||||
public Set<V> get(@Nullable K key) {
|
||||
return (Set<V>) super.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Because a {@code SetMultimap} has unique values for a given key, this method
|
||||
* returns a {@link Set}, instead of the {@link Collection} specified in the
|
||||
* {@link Multimap} interface.
|
||||
*/
|
||||
@Override
|
||||
public Set<Map.Entry<K, V>> entries() {
|
||||
return (Set<Map.Entry<K, V>>) super.entries();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Because a {@code SetMultimap} has unique values for a given key, this method
|
||||
* returns a {@link Set}, instead of the {@link Collection} specified in the
|
||||
* {@link Multimap} interface.
|
||||
*/
|
||||
@Override
|
||||
public Set<V> removeAll(@Nullable Object key) {
|
||||
return (Set<V>) super.removeAll(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Because a {@code SetMultimap} has unique values for a given key, this method
|
||||
* returns a {@link Set}, instead of the {@link Collection} specified in the
|
||||
* {@link Multimap} interface.
|
||||
*
|
||||
* <p>
|
||||
* Any duplicates in {@code values} will be stored in the multimap once.
|
||||
*/
|
||||
@Override
|
||||
public Set<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
|
||||
return (Set<V>) super.replaceValues(key, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Though the method signature doesn't say so explicitly, the returned map has
|
||||
* {@link Set} values.
|
||||
*/
|
||||
@Override
|
||||
public Map<K, Collection<V>> asMap() {
|
||||
return super.asMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a key-value pair in the multimap.
|
||||
*
|
||||
* @param key key to store in the multimap
|
||||
* @param value value to store in the multimap
|
||||
* @return {@code true} if the method increased the size of the multimap, or
|
||||
* {@code false} if the multimap already contained the key-value pair
|
||||
*/
|
||||
@Override
|
||||
public boolean put(@Nullable K key, @Nullable V value) {
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the specified object to this multimap for equality.
|
||||
*
|
||||
* <p>
|
||||
* Two {@code SetMultimap} instances are equal if, for each key, they contain
|
||||
* the same values. Equality does not depend on the ordering of keys or values.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return super.equals(object);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 7431625294878419160L;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Basic implementation of a {@link SortedSetMultimap} with a sorted key set.
|
||||
*
|
||||
* This superclass allows {@code TreeMultimap} to override methods to return
|
||||
* navigable set and map types in non-GWT only, while GWT code will inherit the
|
||||
* SortedMap/SortedSet overrides.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class AbstractSortedKeySortedSetMultimap<K, V> extends AbstractSortedSetMultimap<K, V> {
|
||||
|
||||
AbstractSortedKeySortedSetMultimap(SortedMap<K, Collection<V>> map) {
|
||||
super(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<K, Collection<V>> asMap() {
|
||||
return (SortedMap<K, Collection<V>>) super.asMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
SortedMap<K, Collection<V>> backingMap() {
|
||||
return (SortedMap<K, Collection<V>>) super.backingMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<K> keySet() {
|
||||
return (SortedSet<K>) super.keySet();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* This class provides a skeletal implementation of the {@link SortedMultiset}
|
||||
* interface.
|
||||
*
|
||||
* <p>
|
||||
* The {@link #count} and {@link #size} implementations all iterate across the
|
||||
* set returned by {@link Multiset#entrySet()}, as do many methods acting on the
|
||||
* set returned by {@link #elementSet()}. Override those methods for better
|
||||
* performance.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
abstract class AbstractSortedMultiset<E> extends AbstractMultiset<E> implements SortedMultiset<E> {
|
||||
@GwtTransient
|
||||
final Comparator<? super E> comparator;
|
||||
|
||||
// needed for serialization
|
||||
@SuppressWarnings("unchecked")
|
||||
AbstractSortedMultiset() {
|
||||
this((Comparator) Ordering.natural());
|
||||
}
|
||||
|
||||
AbstractSortedMultiset(Comparator<? super E> comparator) {
|
||||
this.comparator = checkNotNull(comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<E> elementSet() {
|
||||
return (NavigableSet<E>) super.elementSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
NavigableSet<E> createElementSet() {
|
||||
return new SortedMultisets.NavigableElementSet<E>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<? super E> comparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> firstEntry() {
|
||||
Iterator<Entry<E>> entryIterator = entryIterator();
|
||||
return entryIterator.hasNext() ? entryIterator.next() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> lastEntry() {
|
||||
Iterator<Entry<E>> entryIterator = descendingEntryIterator();
|
||||
return entryIterator.hasNext() ? entryIterator.next() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> pollFirstEntry() {
|
||||
Iterator<Entry<E>> entryIterator = entryIterator();
|
||||
if (entryIterator.hasNext()) {
|
||||
Entry<E> result = entryIterator.next();
|
||||
result = Multisets.immutableEntry(result.getElement(), result.getCount());
|
||||
entryIterator.remove();
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> pollLastEntry() {
|
||||
Iterator<Entry<E>> entryIterator = descendingEntryIterator();
|
||||
if (entryIterator.hasNext()) {
|
||||
Entry<E> result = entryIterator.next();
|
||||
result = Multisets.immutableEntry(result.getElement(), result.getCount());
|
||||
entryIterator.remove();
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> subMultiset(@Nullable E fromElement, BoundType fromBoundType, @Nullable E toElement,
|
||||
BoundType toBoundType) {
|
||||
// These are checked elsewhere, but NullPointerTester wants them checked
|
||||
// eagerly.
|
||||
checkNotNull(fromBoundType);
|
||||
checkNotNull(toBoundType);
|
||||
return tailMultiset(fromElement, fromBoundType).headMultiset(toElement, toBoundType);
|
||||
}
|
||||
|
||||
abstract Iterator<Entry<E>> descendingEntryIterator();
|
||||
|
||||
Iterator<E> descendingIterator() {
|
||||
return Multisets.iteratorImpl(descendingMultiset());
|
||||
}
|
||||
|
||||
private transient SortedMultiset<E> descendingMultiset;
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> descendingMultiset() {
|
||||
SortedMultiset<E> result = descendingMultiset;
|
||||
return (result == null) ? descendingMultiset = createDescendingMultiset() : result;
|
||||
}
|
||||
|
||||
SortedMultiset<E> createDescendingMultiset() {
|
||||
return new DescendingMultiset<E>() {
|
||||
@Override
|
||||
SortedMultiset<E> forwardMultiset() {
|
||||
return AbstractSortedMultiset.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
Iterator<Entry<E>> entryIterator() {
|
||||
return descendingEntryIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return descendingIterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Basic implementation of the {@link SortedSetMultimap} interface. It's a
|
||||
* wrapper around {@link AbstractMapBasedMultimap} that converts the returned
|
||||
* collections into sorted sets. The {@link #createCollection} method must
|
||||
* return a {@code SortedSet}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class AbstractSortedSetMultimap<K, V> extends AbstractSetMultimap<K, V> implements SortedSetMultimap<K, V> {
|
||||
/**
|
||||
* Creates a new multimap that uses the provided map.
|
||||
*
|
||||
* @param map place to store the mapping from each key to its corresponding
|
||||
* values
|
||||
*/
|
||||
protected AbstractSortedSetMultimap(Map<K, Collection<V>> map) {
|
||||
super(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract SortedSet<V> createCollection();
|
||||
|
||||
@Override
|
||||
SortedSet<V> createUnmodifiableEmptyCollection() {
|
||||
Comparator<? super V> comparator = valueComparator();
|
||||
if (comparator == null) {
|
||||
return Collections.unmodifiableSortedSet(createCollection());
|
||||
} else {
|
||||
return ImmutableSortedSet.emptySet(valueComparator());
|
||||
}
|
||||
}
|
||||
|
||||
// Following Javadoc copied from Multimap and SortedSetMultimap.
|
||||
|
||||
/**
|
||||
* Returns a collection view of all values associated with a key. If no mappings
|
||||
* in the multimap have the provided key, an empty collection is returned.
|
||||
*
|
||||
* <p>
|
||||
* Changes to the returned collection will update the underlying multimap, and
|
||||
* vice versa.
|
||||
*
|
||||
* <p>
|
||||
* Because a {@code SortedSetMultimap} has unique sorted values for a given key,
|
||||
* this method returns a {@link SortedSet}, instead of the {@link Collection}
|
||||
* specified in the {@link Multimap} interface.
|
||||
*/
|
||||
@Override
|
||||
public SortedSet<V> get(@Nullable K key) {
|
||||
return (SortedSet<V>) super.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all values associated with a given key. The returned collection is
|
||||
* immutable.
|
||||
*
|
||||
* <p>
|
||||
* Because a {@code SortedSetMultimap} has unique sorted values for a given key,
|
||||
* this method returns a {@link SortedSet}, instead of the {@link Collection}
|
||||
* specified in the {@link Multimap} interface.
|
||||
*/
|
||||
@Override
|
||||
public SortedSet<V> removeAll(@Nullable Object key) {
|
||||
return (SortedSet<V>) super.removeAll(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a collection of values with the same key, replacing any existing
|
||||
* values for that key. The returned collection is immutable.
|
||||
*
|
||||
* <p>
|
||||
* Because a {@code SortedSetMultimap} has unique sorted values for a given key,
|
||||
* this method returns a {@link SortedSet}, instead of the {@link Collection}
|
||||
* specified in the {@link Multimap} interface.
|
||||
*
|
||||
* <p>
|
||||
* Any duplicates in {@code values} will be stored in the multimap once.
|
||||
*/
|
||||
@Override
|
||||
public SortedSet<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
|
||||
return (SortedSet<V>) super.replaceValues(key, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map view that associates each key with the corresponding values in
|
||||
* the multimap. Changes to the returned map, such as element removal, will
|
||||
* update the underlying multimap. The map does not support {@code setValue} on
|
||||
* its entries, {@code put}, or {@code putAll}.
|
||||
*
|
||||
* <p>
|
||||
* When passed a key that is present in the map, {@code
|
||||
* asMap().get(Object)} has the same behavior as {@link #get}, returning a live
|
||||
* collection. When passed a key that is not present, however, {@code
|
||||
* asMap().get(Object)} returns {@code null} instead of an empty collection.
|
||||
*
|
||||
* <p>
|
||||
* Though the method signature doesn't say so explicitly, the returned map has
|
||||
* {@link SortedSet} values.
|
||||
*/
|
||||
@Override
|
||||
public Map<K, Collection<V>> asMap() {
|
||||
return super.asMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* Consequently, the values do not follow their natural ordering or the ordering
|
||||
* of the value comparator.
|
||||
*/
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return super.values();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 430848587173315748L;
|
||||
}
|
220
sources/main/java/com/google/common/collect/AbstractTable.java
Normal file
220
sources/main/java/com/google/common/collect/AbstractTable.java
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 com.google.common.collect;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Skeletal, implementation-agnostic implementation of the {@link Table}
|
||||
* interface.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class AbstractTable<R, C, V> implements Table<R, C, V> {
|
||||
|
||||
@Override
|
||||
public boolean containsRow(@Nullable Object rowKey) {
|
||||
return Maps.safeContainsKey(rowMap(), rowKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsColumn(@Nullable Object columnKey) {
|
||||
return Maps.safeContainsKey(columnMap(), columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<R> rowKeySet() {
|
||||
return rowMap().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<C> columnKeySet() {
|
||||
return columnMap().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@Nullable Object value) {
|
||||
for (Map<C, V> row : rowMap().values()) {
|
||||
if (row.containsValue(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
|
||||
return row != null && Maps.safeContainsKey(row, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
|
||||
return (row == null) ? null : Maps.safeGet(row, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
Iterators.clear(cellSet().iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
|
||||
return (row == null) ? null : Maps.safeRemove(row, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(R rowKey, C columnKey, V value) {
|
||||
return row(rowKey).put(columnKey, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
|
||||
for (Table.Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) {
|
||||
put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private transient Set<Cell<R, C, V>> cellSet;
|
||||
|
||||
@Override
|
||||
public Set<Cell<R, C, V>> cellSet() {
|
||||
Set<Cell<R, C, V>> result = cellSet;
|
||||
return (result == null) ? cellSet = createCellSet() : result;
|
||||
}
|
||||
|
||||
Set<Cell<R, C, V>> createCellSet() {
|
||||
return new CellSet();
|
||||
}
|
||||
|
||||
abstract Iterator<Table.Cell<R, C, V>> cellIterator();
|
||||
|
||||
class CellSet extends AbstractSet<Cell<R, C, V>> {
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o instanceof Cell) {
|
||||
Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o;
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey());
|
||||
return row != null && Collections2.safeContains(row.entrySet(),
|
||||
Maps.immutableEntry(cell.getColumnKey(), cell.getValue()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(@Nullable Object o) {
|
||||
if (o instanceof Cell) {
|
||||
Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o;
|
||||
Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey());
|
||||
return row != null && Collections2.safeRemove(row.entrySet(),
|
||||
Maps.immutableEntry(cell.getColumnKey(), cell.getValue()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
AbstractTable.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Table.Cell<R, C, V>> iterator() {
|
||||
return cellIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return AbstractTable.this.size();
|
||||
}
|
||||
}
|
||||
|
||||
private transient Collection<V> values;
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
Collection<V> result = values;
|
||||
return (result == null) ? values = createValues() : result;
|
||||
}
|
||||
|
||||
Collection<V> createValues() {
|
||||
return new Values();
|
||||
}
|
||||
|
||||
Iterator<V> valuesIterator() {
|
||||
return new TransformedIterator<Cell<R, C, V>, V>(cellSet().iterator()) {
|
||||
@Override
|
||||
V transform(Cell<R, C, V> cell) {
|
||||
return cell.getValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class Values extends AbstractCollection<V> {
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return valuesIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return containsValue(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
AbstractTable.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return AbstractTable.this.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return Tables.equalsImpl(this, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return cellSet().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string representation {@code rowMap().toString()}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return rowMap().toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* An ordering that treats all references as equals, even nulls.
|
||||
*
|
||||
* @author Emily Soldal
|
||||
*/
|
||||
@GwtCompatible(serializable = true)
|
||||
final class AllEqualOrdering extends Ordering<Object> implements Serializable {
|
||||
static final AllEqualOrdering INSTANCE = new AllEqualOrdering();
|
||||
|
||||
@Override
|
||||
public int compare(@Nullable Object left, @Nullable Object right) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> List<E> sortedCopy(Iterable<E> iterable) {
|
||||
return Lists.newArrayList(iterable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> ImmutableList<E> immutableSortedCopy(Iterable<E> iterable) {
|
||||
return ImmutableList.copyOf(iterable);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <S> Ordering<S> reverse() {
|
||||
return (Ordering<S>) this;
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Ordering.allEqual()";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Implementation of {@code Multimap} that uses an {@code ArrayList} to store
|
||||
* the values for a given key. A {@link HashMap} associates each key with an
|
||||
* {@link ArrayList} of values.
|
||||
*
|
||||
* <p>
|
||||
* When iterating through the collections supplied by this class, the ordering
|
||||
* of values for a given key agrees with the order in which the values were
|
||||
* added.
|
||||
*
|
||||
* <p>
|
||||
* This multimap allows duplicate key-value pairs. After adding a new key-value
|
||||
* pair equal to an existing key-value pair, the {@code
|
||||
* ArrayListMultimap} will contain entries for both the new value and the old
|
||||
* value.
|
||||
*
|
||||
* <p>
|
||||
* Keys and values may be null. All optional multimap methods are supported, and
|
||||
* all returned views are modifiable.
|
||||
*
|
||||
* <p>
|
||||
* The lists returned by {@link #get}, {@link #removeAll}, and
|
||||
* {@link #replaceValues} all implement {@link net.lax1dude.eaglercraft.v1_8.RandomAccess}.
|
||||
*
|
||||
* <p>
|
||||
* This class is not threadsafe when any concurrent operations update the
|
||||
* multimap. Concurrent read operations will work correctly. To allow concurrent
|
||||
* update operations, wrap your multimap with a call to
|
||||
* {@link Multimaps#synchronizedListMultimap}.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
|
||||
* {@code Multimap}</a>.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible(serializable = true, emulated = true)
|
||||
public final class ArrayListMultimap<K, V> extends AbstractListMultimap<K, V> {
|
||||
// Default from ArrayList
|
||||
private static final int DEFAULT_VALUES_PER_KEY = 3;
|
||||
|
||||
@VisibleForTesting
|
||||
transient int expectedValuesPerKey;
|
||||
|
||||
/**
|
||||
* Creates a new, empty {@code ArrayListMultimap} with the default initial
|
||||
* capacities.
|
||||
*/
|
||||
public static <K, V> ArrayListMultimap<K, V> create() {
|
||||
return new ArrayListMultimap<K, V>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code ArrayListMultimap} with enough capacity to hold
|
||||
* the specified numbers of keys and values without resizing.
|
||||
*
|
||||
* @param expectedKeys the expected number of distinct keys
|
||||
* @param expectedValuesPerKey the expected average number of values per key
|
||||
* @throws IllegalArgumentException if {@code expectedKeys} or {@code
|
||||
* expectedValuesPerKey} is negative
|
||||
*/
|
||||
public static <K, V> ArrayListMultimap<K, V> create(int expectedKeys, int expectedValuesPerKey) {
|
||||
return new ArrayListMultimap<K, V>(expectedKeys, expectedValuesPerKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an {@code ArrayListMultimap} with the same mappings as the
|
||||
* specified multimap.
|
||||
*
|
||||
* @param multimap the multimap whose contents are copied to this multimap
|
||||
*/
|
||||
public static <K, V> ArrayListMultimap<K, V> create(Multimap<? extends K, ? extends V> multimap) {
|
||||
return new ArrayListMultimap<K, V>(multimap);
|
||||
}
|
||||
|
||||
private ArrayListMultimap() {
|
||||
super(new HashMap<K, Collection<V>>());
|
||||
expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
|
||||
}
|
||||
|
||||
private ArrayListMultimap(int expectedKeys, int expectedValuesPerKey) {
|
||||
super(Maps.<K, Collection<V>>newHashMapWithExpectedSize(expectedKeys));
|
||||
checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey");
|
||||
this.expectedValuesPerKey = expectedValuesPerKey;
|
||||
}
|
||||
|
||||
private ArrayListMultimap(Multimap<? extends K, ? extends V> multimap) {
|
||||
this(multimap.keySet().size(),
|
||||
(multimap instanceof ArrayListMultimap) ? ((ArrayListMultimap<?, ?>) multimap).expectedValuesPerKey
|
||||
: DEFAULT_VALUES_PER_KEY);
|
||||
putAll(multimap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new, empty {@code ArrayList} to hold the collection of values for
|
||||
* an arbitrary key.
|
||||
*/
|
||||
@Override
|
||||
List<V> createCollection() {
|
||||
return new ArrayList<V>(expectedValuesPerKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the memory used by this {@code ArrayListMultimap}, if feasible.
|
||||
*/
|
||||
public void trimToSize() {
|
||||
for (Collection<V> collection : backingMap().values()) {
|
||||
ArrayList<V> arrayList = (ArrayList<V>) collection;
|
||||
arrayList.trimToSize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData expectedValuesPerKey, number of distinct keys, and then for each
|
||||
* distinct key: the key, number of values for that key, and the
|
||||
* key's values
|
||||
*/
|
||||
@GwtIncompatible("java.io.ObjectOutputStream")
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
stream.writeInt(expectedValuesPerKey);
|
||||
Serialization.writeMultimap(this, stream);
|
||||
}
|
||||
|
||||
@GwtIncompatible("java.io.ObjectOutputStream")
|
||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
expectedValuesPerKey = stream.readInt();
|
||||
int distinctKeys = Serialization.readCount(stream);
|
||||
Map<K, Collection<V>> map = Maps.newHashMapWithExpectedSize(distinctKeys);
|
||||
setMap(map);
|
||||
Serialization.populateMultimap(this, stream, distinctKeys);
|
||||
}
|
||||
|
||||
@GwtIncompatible("Not needed in emulated source.")
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
793
sources/main/java/com/google/common/collect/ArrayTable.java
Normal file
793
sources/main/java/com/google/common/collect/ArrayTable.java
Normal file
@ -0,0 +1,793 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkElementIndex;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Fixed-size {@link Table} implementation backed by a two-dimensional array.
|
||||
*
|
||||
* <p>
|
||||
* The allowed row and column keys must be supplied when the table is created.
|
||||
* The table always contains a mapping for every row key / column pair. The
|
||||
* value corresponding to a given row and column is null unless another value is
|
||||
* provided.
|
||||
*
|
||||
* <p>
|
||||
* The table's size is constant: the product of the number of supplied row keys
|
||||
* and the number of supplied column keys. The {@code remove} and {@code
|
||||
* clear} methods are not supported by the table or its views. The
|
||||
* {@link #erase} and {@link #eraseAll} methods may be used instead.
|
||||
*
|
||||
* <p>
|
||||
* The ordering of the row and column keys provided when the table is
|
||||
* constructed determines the iteration ordering across rows and columns in the
|
||||
* table's views. None of the view iterators support {@link Iterator#remove}. If
|
||||
* the table is modified after an iterator is created, the iterator remains
|
||||
* valid.
|
||||
*
|
||||
* <p>
|
||||
* This class requires less memory than the {@link HashBasedTable} and
|
||||
* {@link TreeBasedTable} implementations, except when the table is sparse.
|
||||
*
|
||||
* <p>
|
||||
* Null row keys or column keys are not permitted.
|
||||
*
|
||||
* <p>
|
||||
* This class provides methods involving the underlying array structure, where
|
||||
* the array indices correspond to the position of a row or column in the lists
|
||||
* of allowed keys and values. See the {@link #at}, {@link #set},
|
||||
* {@link #toArray}, {@link #rowKeyList}, and {@link #columnKeyList} methods for
|
||||
* more details.
|
||||
*
|
||||
* <p>
|
||||
* Note that this implementation is not synchronized. If multiple threads access
|
||||
* the same cell of an {@code ArrayTable} concurrently and one of the threads
|
||||
* modifies its value, there is no guarantee that the new value will be fully
|
||||
* visible to the other threads. To guarantee that modifications are visible,
|
||||
* synchronize access to the table. Unlike other {@code Table} implementations,
|
||||
* synchronization is unnecessary between a thread that writes to one cell and a
|
||||
* thread that reads from another.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table">
|
||||
* {@code Table}</a>.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @since 10.0
|
||||
*/
|
||||
@Beta
|
||||
@GwtCompatible(emulated = true)
|
||||
public final class ArrayTable<R, C, V> extends AbstractTable<R, C, V> implements Serializable {
|
||||
|
||||
/**
|
||||
* Creates an empty {@code ArrayTable}.
|
||||
*
|
||||
* @param rowKeys row keys that may be stored in the generated table
|
||||
* @param columnKeys column keys that may be stored in the generated table
|
||||
* @throws NullPointerException if any of the provided keys is null
|
||||
* @throws IllegalArgumentException if {@code rowKeys} or {@code columnKeys}
|
||||
* contains duplicates or is empty
|
||||
*/
|
||||
public static <R, C, V> ArrayTable<R, C, V> create(Iterable<? extends R> rowKeys,
|
||||
Iterable<? extends C> columnKeys) {
|
||||
return new ArrayTable<R, C, V>(rowKeys, columnKeys);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(jlevy): Add factory methods taking an Enum class, instead of an
|
||||
* iterable, to specify the allowed row keys and/or column keys. Note that
|
||||
* custom serialization logic is needed to support different enum sizes during
|
||||
* serialization and deserialization.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates an {@code ArrayTable} with the mappings in the provided table.
|
||||
*
|
||||
* <p>
|
||||
* If {@code table} includes a mapping with row key {@code r} and a separate
|
||||
* mapping with column key {@code c}, the returned table contains a mapping with
|
||||
* row key {@code r} and column key {@code c}. If that row key / column key pair
|
||||
* in not in {@code table}, the pair maps to {@code null} in the generated
|
||||
* table.
|
||||
*
|
||||
* <p>
|
||||
* The returned table allows subsequent {@code put} calls with the row keys in
|
||||
* {@code table.rowKeySet()} and the column keys in {@code
|
||||
* table.columnKeySet()}. Calling {@link #put} with other keys leads to an
|
||||
* {@code IllegalArgumentException}.
|
||||
*
|
||||
* <p>
|
||||
* The ordering of {@code table.rowKeySet()} and {@code
|
||||
* table.columnKeySet()} determines the row and column iteration ordering of the
|
||||
* returned table.
|
||||
*
|
||||
* @throws NullPointerException if {@code table} has a null key
|
||||
* @throws IllegalArgumentException if the provided table is empty
|
||||
*/
|
||||
public static <R, C, V> ArrayTable<R, C, V> create(Table<R, C, V> table) {
|
||||
return (table instanceof ArrayTable<?, ?, ?>) ? new ArrayTable<R, C, V>((ArrayTable<R, C, V>) table)
|
||||
: new ArrayTable<R, C, V>(table);
|
||||
}
|
||||
|
||||
private final ImmutableList<R> rowList;
|
||||
private final ImmutableList<C> columnList;
|
||||
|
||||
// TODO(jlevy): Add getters returning rowKeyToIndex and columnKeyToIndex?
|
||||
private final ImmutableMap<R, Integer> rowKeyToIndex;
|
||||
private final ImmutableMap<C, Integer> columnKeyToIndex;
|
||||
private final V[][] array;
|
||||
|
||||
private ArrayTable(Iterable<? extends R> rowKeys, Iterable<? extends C> columnKeys) {
|
||||
this.rowList = ImmutableList.copyOf(rowKeys);
|
||||
this.columnList = ImmutableList.copyOf(columnKeys);
|
||||
checkArgument(!rowList.isEmpty());
|
||||
checkArgument(!columnList.isEmpty());
|
||||
|
||||
/*
|
||||
* TODO(jlevy): Support empty rowKeys or columnKeys? If we do, when columnKeys
|
||||
* is empty but rowKeys isn't, the table is empty but containsRow() can return
|
||||
* true and rowKeySet() isn't empty.
|
||||
*/
|
||||
rowKeyToIndex = index(rowList);
|
||||
columnKeyToIndex = index(columnList);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
V[][] tmpArray = (V[][]) new Object[rowList.size()][columnList.size()];
|
||||
array = tmpArray;
|
||||
// Necessary because in GWT the arrays are initialized with "undefined" instead
|
||||
// of null.
|
||||
eraseAll();
|
||||
}
|
||||
|
||||
private static <E> ImmutableMap<E, Integer> index(List<E> list) {
|
||||
ImmutableMap.Builder<E, Integer> columnBuilder = ImmutableMap.builder();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
columnBuilder.put(list.get(i), i);
|
||||
}
|
||||
return columnBuilder.build();
|
||||
}
|
||||
|
||||
private ArrayTable(Table<R, C, V> table) {
|
||||
this(table.rowKeySet(), table.columnKeySet());
|
||||
putAll(table);
|
||||
}
|
||||
|
||||
private ArrayTable(ArrayTable<R, C, V> table) {
|
||||
rowList = table.rowList;
|
||||
columnList = table.columnList;
|
||||
rowKeyToIndex = table.rowKeyToIndex;
|
||||
columnKeyToIndex = table.columnKeyToIndex;
|
||||
@SuppressWarnings("unchecked")
|
||||
V[][] copy = (V[][]) new Object[rowList.size()][columnList.size()];
|
||||
array = copy;
|
||||
// Necessary because in GWT the arrays are initialized with "undefined" instead
|
||||
// of null.
|
||||
eraseAll();
|
||||
for (int i = 0; i < rowList.size(); i++) {
|
||||
System.arraycopy(table.array[i], 0, copy[i], 0, table.array[i].length);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class ArrayMap<K, V> extends Maps.ImprovedAbstractMap<K, V> {
|
||||
private final ImmutableMap<K, Integer> keyIndex;
|
||||
|
||||
private ArrayMap(ImmutableMap<K, Integer> keyIndex) {
|
||||
this.keyIndex = keyIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return keyIndex.keySet();
|
||||
}
|
||||
|
||||
K getKey(int index) {
|
||||
return keyIndex.keySet().asList().get(index);
|
||||
}
|
||||
|
||||
abstract String getKeyRole();
|
||||
|
||||
@Nullable
|
||||
abstract V getValue(int index);
|
||||
|
||||
@Nullable
|
||||
abstract V setValue(int index, V newValue);
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return keyIndex.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return keyIndex.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Entry<K, V>> createEntrySet() {
|
||||
return new Maps.EntrySet<K, V>() {
|
||||
@Override
|
||||
Map<K, V> map() {
|
||||
return ArrayMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
return new AbstractIndexedListIterator<Entry<K, V>>(size()) {
|
||||
@Override
|
||||
protected Entry<K, V> get(final int index) {
|
||||
return new AbstractMapEntry<K, V>() {
|
||||
@Override
|
||||
public K getKey() {
|
||||
return ArrayMap.this.getKey(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return ArrayMap.this.getValue(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
return ArrayMap.this.setValue(index, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// TODO(user): consider an optimized values() implementation
|
||||
|
||||
@Override
|
||||
public boolean containsKey(@Nullable Object key) {
|
||||
return keyIndex.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(@Nullable Object key) {
|
||||
Integer index = keyIndex.get(key);
|
||||
if (index == null) {
|
||||
return null;
|
||||
} else {
|
||||
return getValue(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
Integer index = keyIndex.get(key);
|
||||
if (index == null) {
|
||||
throw new IllegalArgumentException(getKeyRole() + " " + key + " not in " + keyIndex.keySet());
|
||||
}
|
||||
return setValue(index, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, as an immutable list, the row keys provided when the table was
|
||||
* constructed, including those that are mapped to null values only.
|
||||
*/
|
||||
public ImmutableList<R> rowKeyList() {
|
||||
return rowList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns, as an immutable list, the column keys provided when the table was
|
||||
* constructed, including those that are mapped to null values only.
|
||||
*/
|
||||
public ImmutableList<C> columnKeyList() {
|
||||
return columnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value corresponding to the specified row and column indices. The
|
||||
* same value is returned by {@code
|
||||
* get(rowKeyList().get(rowIndex), columnKeyList().get(columnIndex))}, but this
|
||||
* method runs more quickly.
|
||||
*
|
||||
* @param rowIndex position of the row key in {@link #rowKeyList()}
|
||||
* @param columnIndex position of the row key in {@link #columnKeyList()}
|
||||
* @return the value with the specified row and column
|
||||
* @throws IndexOutOfBoundsException if either index is negative, {@code
|
||||
* rowIndex} is greater then or equal to the number of
|
||||
* allowed row keys, or {@code columnIndex} is
|
||||
* greater then or equal to the number of
|
||||
* allowed column keys
|
||||
*/
|
||||
public V at(int rowIndex, int columnIndex) {
|
||||
// In GWT array access never throws IndexOutOfBoundsException.
|
||||
checkElementIndex(rowIndex, rowList.size());
|
||||
checkElementIndex(columnIndex, columnList.size());
|
||||
return array[rowIndex][columnIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates {@code value} with the specified row and column indices. The logic
|
||||
* {@code
|
||||
* put(rowKeyList().get(rowIndex), columnKeyList().get(columnIndex), value)} has
|
||||
* the same behavior, but this method runs more quickly.
|
||||
*
|
||||
* @param rowIndex position of the row key in {@link #rowKeyList()}
|
||||
* @param columnIndex position of the row key in {@link #columnKeyList()}
|
||||
* @param value value to store in the table
|
||||
* @return the previous value with the specified row and column
|
||||
* @throws IndexOutOfBoundsException if either index is negative, {@code
|
||||
* rowIndex} is greater then or equal to the number of
|
||||
* allowed row keys, or {@code columnIndex} is
|
||||
* greater then or equal to the number of
|
||||
* allowed column keys
|
||||
*/
|
||||
public V set(int rowIndex, int columnIndex, @Nullable V value) {
|
||||
// In GWT array access never throws IndexOutOfBoundsException.
|
||||
checkElementIndex(rowIndex, rowList.size());
|
||||
checkElementIndex(columnIndex, columnList.size());
|
||||
V oldValue = array[rowIndex][columnIndex];
|
||||
array[rowIndex][columnIndex] = value;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a two-dimensional array with the table contents. The row and column
|
||||
* indices correspond to the positions of the row and column in the iterables
|
||||
* provided during table construction. If the table lacks a mapping for a given
|
||||
* row and column, the corresponding array element is null.
|
||||
*
|
||||
* <p>
|
||||
* Subsequent table changes will not modify the array, and vice versa.
|
||||
*
|
||||
* @param valueClass class of values stored in the returned array
|
||||
*/
|
||||
@GwtIncompatible("reflection")
|
||||
public V[][] toArray(Class<V> valueClass) {
|
||||
// Can change to use varargs in JDK 1.6 if we want
|
||||
@SuppressWarnings("unchecked") // TODO: safe?
|
||||
V[][] copy = (V[][]) Array.newInstance(valueClass, new int[] { rowList.size(), columnList.size() });
|
||||
for (int i = 0; i < rowList.size(); i++) {
|
||||
System.arraycopy(array[i], 0, copy[i], 0, array[i].length);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported. Use {@link #eraseAll} instead.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Use {@link #eraseAll}
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the value {@code null} with every pair of allowed row and column
|
||||
* keys.
|
||||
*/
|
||||
public void eraseAll() {
|
||||
for (V[] row : array) {
|
||||
Arrays.fill(row, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the provided keys are among the keys provided when
|
||||
* the table was constructed.
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
return containsRow(rowKey) && containsColumn(columnKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the provided column key is among the column keys
|
||||
* provided when the table was constructed.
|
||||
*/
|
||||
@Override
|
||||
public boolean containsColumn(@Nullable Object columnKey) {
|
||||
return columnKeyToIndex.containsKey(columnKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the provided row key is among the row keys provided
|
||||
* when the table was constructed.
|
||||
*/
|
||||
@Override
|
||||
public boolean containsRow(@Nullable Object rowKey) {
|
||||
return rowKeyToIndex.containsKey(rowKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@Nullable Object value) {
|
||||
for (V[] row : array) {
|
||||
for (V element : row) {
|
||||
if (Objects.equal(value, element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
Integer rowIndex = rowKeyToIndex.get(rowKey);
|
||||
Integer columnIndex = columnKeyToIndex.get(columnKey);
|
||||
return (rowIndex == null || columnIndex == null) ? null : at(rowIndex, columnIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code false}.
|
||||
*/
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code rowKey} is not in
|
||||
* {@link #rowKeySet()} or {@code columnKey} is
|
||||
* not in {@link #columnKeySet()}.
|
||||
*/
|
||||
@Override
|
||||
public V put(R rowKey, C columnKey, @Nullable V value) {
|
||||
checkNotNull(rowKey);
|
||||
checkNotNull(columnKey);
|
||||
Integer rowIndex = rowKeyToIndex.get(rowKey);
|
||||
checkArgument(rowIndex != null, "Row %s not in %s", rowKey, rowList);
|
||||
Integer columnIndex = columnKeyToIndex.get(columnKey);
|
||||
checkArgument(columnIndex != null, "Column %s not in %s", columnKey, columnList);
|
||||
return set(rowIndex, columnIndex, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(jlevy): Consider creating a merge() method, similar to putAll() but
|
||||
* copying non-null values only.
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* If {@code table} is an {@code ArrayTable}, its null values will be stored in
|
||||
* this table, possibly replacing values that were previously non-null.
|
||||
*
|
||||
* @throws NullPointerException if {@code table} has a null key
|
||||
* @throws IllegalArgumentException if any of the provided table's row keys or
|
||||
* column keys is not in {@link #rowKeySet()}
|
||||
* or {@link #columnKeySet()}
|
||||
*/
|
||||
@Override
|
||||
public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
|
||||
super.putAll(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported. Use {@link #erase} instead.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Use {@link #erase}
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public V remove(Object rowKey, Object columnKey) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the value {@code null} with the specified keys, assuming both keys
|
||||
* are valid. If either key is null or isn't among the keys provided during
|
||||
* construction, this method has no effect.
|
||||
*
|
||||
* <p>
|
||||
* This method is equivalent to {@code put(rowKey, columnKey, null)} when both
|
||||
* provided keys are valid.
|
||||
*
|
||||
* @param rowKey row key of mapping to be erased
|
||||
* @param columnKey column key of mapping to be erased
|
||||
* @return the value previously associated with the keys, or {@code null} if no
|
||||
* mapping existed for the keys
|
||||
*/
|
||||
public V erase(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
Integer rowIndex = rowKeyToIndex.get(rowKey);
|
||||
Integer columnIndex = columnKeyToIndex.get(columnKey);
|
||||
if (rowIndex == null || columnIndex == null) {
|
||||
return null;
|
||||
}
|
||||
return set(rowIndex, columnIndex, null);
|
||||
}
|
||||
|
||||
// TODO(jlevy): Add eraseRow and eraseColumn methods?
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return rowList.size() * columnList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable set of all row key / column key / value triplets.
|
||||
* Changes to the table will update the returned set.
|
||||
*
|
||||
* <p>
|
||||
* The returned set's iterator traverses the mappings with the first row key,
|
||||
* the mappings with the second row key, and so on.
|
||||
*
|
||||
* <p>
|
||||
* The value in the returned cells may change if the table subsequently changes.
|
||||
*
|
||||
* @return set of table cells consisting of row key / column key / value
|
||||
* triplets
|
||||
*/
|
||||
@Override
|
||||
public Set<Cell<R, C, V>> cellSet() {
|
||||
return super.cellSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
Iterator<Cell<R, C, V>> cellIterator() {
|
||||
return new AbstractIndexedListIterator<Cell<R, C, V>>(size()) {
|
||||
@Override
|
||||
protected Cell<R, C, V> get(final int index) {
|
||||
return new Tables.AbstractCell<R, C, V>() {
|
||||
final int rowIndex = index / columnList.size();
|
||||
final int columnIndex = index % columnList.size();
|
||||
|
||||
@Override
|
||||
public R getRowKey() {
|
||||
return rowList.get(rowIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public C getColumnKey() {
|
||||
return columnList.get(columnIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return at(rowIndex, columnIndex);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of all mappings that have the given column key. If the column
|
||||
* key isn't in {@link #columnKeySet()}, an empty immutable map is returned.
|
||||
*
|
||||
* <p>
|
||||
* Otherwise, for each row key in {@link #rowKeySet()}, the returned map
|
||||
* associates the row key with the corresponding value in the table. Changes to
|
||||
* the returned map will update the underlying table, and vice versa.
|
||||
*
|
||||
* @param columnKey key of column to search for in the table
|
||||
* @return the corresponding map from row keys to values
|
||||
*/
|
||||
@Override
|
||||
public Map<R, V> column(C columnKey) {
|
||||
checkNotNull(columnKey);
|
||||
Integer columnIndex = columnKeyToIndex.get(columnKey);
|
||||
return (columnIndex == null) ? ImmutableMap.<R, V>of() : new Column(columnIndex);
|
||||
}
|
||||
|
||||
private class Column extends ArrayMap<R, V> {
|
||||
final int columnIndex;
|
||||
|
||||
Column(int columnIndex) {
|
||||
super(rowKeyToIndex);
|
||||
this.columnIndex = columnIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getKeyRole() {
|
||||
return "Row";
|
||||
}
|
||||
|
||||
@Override
|
||||
V getValue(int index) {
|
||||
return at(index, columnIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
V setValue(int index, V newValue) {
|
||||
return set(index, columnIndex, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set of the valid column keys, including those that are
|
||||
* associated with null values only.
|
||||
*
|
||||
* @return immutable set of column keys
|
||||
*/
|
||||
@Override
|
||||
public ImmutableSet<C> columnKeySet() {
|
||||
return columnKeyToIndex.keySet();
|
||||
}
|
||||
|
||||
private transient ColumnMap columnMap;
|
||||
|
||||
@Override
|
||||
public Map<C, Map<R, V>> columnMap() {
|
||||
ColumnMap map = columnMap;
|
||||
return (map == null) ? columnMap = new ColumnMap() : map;
|
||||
}
|
||||
|
||||
private class ColumnMap extends ArrayMap<C, Map<R, V>> {
|
||||
private ColumnMap() {
|
||||
super(columnKeyToIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getKeyRole() {
|
||||
return "Column";
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<R, V> getValue(int index) {
|
||||
return new Column(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<R, V> setValue(int index, Map<R, V> newValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<R, V> put(C key, Map<R, V> value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of all mappings that have the given row key. If the row key
|
||||
* isn't in {@link #rowKeySet()}, an empty immutable map is returned.
|
||||
*
|
||||
* <p>
|
||||
* Otherwise, for each column key in {@link #columnKeySet()}, the returned map
|
||||
* associates the column key with the corresponding value in the table. Changes
|
||||
* to the returned map will update the underlying table, and vice versa.
|
||||
*
|
||||
* @param rowKey key of row to search for in the table
|
||||
* @return the corresponding map from column keys to values
|
||||
*/
|
||||
@Override
|
||||
public Map<C, V> row(R rowKey) {
|
||||
checkNotNull(rowKey);
|
||||
Integer rowIndex = rowKeyToIndex.get(rowKey);
|
||||
return (rowIndex == null) ? ImmutableMap.<C, V>of() : new Row(rowIndex);
|
||||
}
|
||||
|
||||
private class Row extends ArrayMap<C, V> {
|
||||
final int rowIndex;
|
||||
|
||||
Row(int rowIndex) {
|
||||
super(columnKeyToIndex);
|
||||
this.rowIndex = rowIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getKeyRole() {
|
||||
return "Column";
|
||||
}
|
||||
|
||||
@Override
|
||||
V getValue(int index) {
|
||||
return at(rowIndex, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
V setValue(int index, V newValue) {
|
||||
return set(rowIndex, index, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set of the valid row keys, including those that are
|
||||
* associated with null values only.
|
||||
*
|
||||
* @return immutable set of row keys
|
||||
*/
|
||||
@Override
|
||||
public ImmutableSet<R> rowKeySet() {
|
||||
return rowKeyToIndex.keySet();
|
||||
}
|
||||
|
||||
private transient RowMap rowMap;
|
||||
|
||||
@Override
|
||||
public Map<R, Map<C, V>> rowMap() {
|
||||
RowMap map = rowMap;
|
||||
return (map == null) ? rowMap = new RowMap() : map;
|
||||
}
|
||||
|
||||
private class RowMap extends ArrayMap<R, Map<C, V>> {
|
||||
private RowMap() {
|
||||
super(rowKeyToIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getKeyRole() {
|
||||
return "Row";
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<C, V> getValue(int index) {
|
||||
return new Row(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<C, V> setValue(int index, Map<C, V> newValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<C, V> put(R key, Map<C, V> value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable collection of all values, which may contain
|
||||
* duplicates. Changes to the table will update the returned collection.
|
||||
*
|
||||
* <p>
|
||||
* The returned collection's iterator traverses the values of the first row key,
|
||||
* the values of the second row key, and so on.
|
||||
*
|
||||
* @return collection of values
|
||||
*/
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return super.values();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
118
sources/main/java/com/google/common/collect/BiMap.java
Normal file
118
sources/main/java/com/google/common/collect/BiMap.java
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A bimap (or "bidirectional map") is a map that preserves the uniqueness of
|
||||
* its values as well as that of its keys. This constraint enables bimaps to
|
||||
* support an "inverse view", which is another bimap containing the same entries
|
||||
* as this bimap but with reversed keys and values.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
|
||||
* {@code BiMap}</a>.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public interface BiMap<K, V> extends Map<K, V> {
|
||||
// Modification Operations
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws IllegalArgumentException if the given value is already bound to a
|
||||
* different key in this bimap. The bimap will
|
||||
* remain unmodified in this event. To avoid
|
||||
* this exception, call {@link #forcePut}
|
||||
* instead.
|
||||
*/
|
||||
@Override
|
||||
V put(@Nullable K key, @Nullable V value);
|
||||
|
||||
/**
|
||||
* An alternate form of {@code put} that silently removes any existing entry
|
||||
* with the value {@code value} before proceeding with the {@link #put}
|
||||
* operation. If the bimap previously contained the provided key-value mapping,
|
||||
* this method has no effect.
|
||||
*
|
||||
* <p>
|
||||
* Note that a successful call to this method could cause the size of the bimap
|
||||
* to increase by one, stay the same, or even decrease by one.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> If an existing entry with this value is removed, the key for
|
||||
* that entry is discarded and not returned.
|
||||
*
|
||||
* @param key the key with which the specified value is to be associated
|
||||
* @param value the value to be associated with the specified key
|
||||
* @return the value which was previously associated with the key, which may be
|
||||
* {@code null}, or {@code null} if there was no previous entry
|
||||
*/
|
||||
V forcePut(@Nullable K key, @Nullable V value);
|
||||
|
||||
// Bulk Operations
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> the results of calling this method may vary depending on the
|
||||
* iteration order of {@code map}.
|
||||
*
|
||||
* @throws IllegalArgumentException if an attempt to {@code put} any entry
|
||||
* fails. Note that some map entries may have
|
||||
* been added to the bimap before the exception
|
||||
* was thrown.
|
||||
*/
|
||||
@Override
|
||||
void putAll(Map<? extends K, ? extends V> map);
|
||||
|
||||
// Views
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Because a bimap has unique values, this method returns a {@link Set}, instead
|
||||
* of the {@link java.util.Collection} specified in the {@link Map} interface.
|
||||
*/
|
||||
@Override
|
||||
Set<V> values();
|
||||
|
||||
/**
|
||||
* Returns the inverse view of this bimap, which maps each of this bimap's
|
||||
* values to its associated key. The two bimaps are backed by the same data; any
|
||||
* changes to one will appear in the other.
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b>There is no guaranteed correspondence between the iteration order
|
||||
* of a bimap and that of its inverse.
|
||||
*
|
||||
* @return the inverse view of this bimap
|
||||
*/
|
||||
BiMap<V, K> inverse();
|
||||
}
|
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.BitSet;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
/**
|
||||
* A variant of {@link TreeTraverser} for binary trees, providing additional
|
||||
* traversals specific to binary trees.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
* @since 15.0
|
||||
*/
|
||||
@Beta
|
||||
@GwtCompatible(emulated = true)
|
||||
public abstract class BinaryTreeTraverser<T> extends TreeTraverser<T> {
|
||||
// TODO(user): make this GWT-compatible when we've checked in ArrayDeque and
|
||||
// BitSet emulation
|
||||
|
||||
/**
|
||||
* Returns the left child of the specified node, or {@link Optional#absent()} if
|
||||
* the specified node has no left child.
|
||||
*/
|
||||
public abstract Optional<T> leftChild(T root);
|
||||
|
||||
/**
|
||||
* Returns the right child of the specified node, or {@link Optional#absent()}
|
||||
* if the specified node has no right child.
|
||||
*/
|
||||
public abstract Optional<T> rightChild(T root);
|
||||
|
||||
/**
|
||||
* Returns the children of this node, in left-to-right order.
|
||||
*/
|
||||
@Override
|
||||
public final Iterable<T> children(final T root) {
|
||||
checkNotNull(root);
|
||||
return new FluentIterable<T>() {
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new AbstractIterator<T>() {
|
||||
boolean doneLeft;
|
||||
boolean doneRight;
|
||||
|
||||
@Override
|
||||
protected T computeNext() {
|
||||
if (!doneLeft) {
|
||||
doneLeft = true;
|
||||
Optional<T> left = leftChild(root);
|
||||
if (left.isPresent()) {
|
||||
return left.get();
|
||||
}
|
||||
}
|
||||
if (!doneRight) {
|
||||
doneRight = true;
|
||||
Optional<T> right = rightChild(root);
|
||||
if (right.isPresent()) {
|
||||
return right.get();
|
||||
}
|
||||
}
|
||||
return endOfData();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
UnmodifiableIterator<T> preOrderIterator(T root) {
|
||||
return new PreOrderIterator(root);
|
||||
}
|
||||
|
||||
/*
|
||||
* Optimized implementation of preOrderIterator for binary trees.
|
||||
*/
|
||||
private final class PreOrderIterator extends UnmodifiableIterator<T> implements PeekingIterator<T> {
|
||||
private final Deque<T> stack;
|
||||
|
||||
PreOrderIterator(T root) {
|
||||
this.stack = new ArrayDeque<T>();
|
||||
stack.addLast(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return !stack.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
T result = stack.removeLast();
|
||||
pushIfPresent(stack, rightChild(result));
|
||||
pushIfPresent(stack, leftChild(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T peek() {
|
||||
return stack.getLast();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
UnmodifiableIterator<T> postOrderIterator(T root) {
|
||||
return new PostOrderIterator(root);
|
||||
}
|
||||
|
||||
/*
|
||||
* Optimized implementation of postOrderIterator for binary trees.
|
||||
*/
|
||||
private final class PostOrderIterator extends UnmodifiableIterator<T> {
|
||||
private final Deque<T> stack;
|
||||
private final BitSet hasExpanded;
|
||||
|
||||
PostOrderIterator(T root) {
|
||||
this.stack = new ArrayDeque<T>();
|
||||
stack.addLast(root);
|
||||
this.hasExpanded = new BitSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return !stack.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
while (true) {
|
||||
T node = stack.getLast();
|
||||
boolean expandedNode = hasExpanded.get(stack.size() - 1);
|
||||
if (expandedNode) {
|
||||
stack.removeLast();
|
||||
hasExpanded.clear(stack.size());
|
||||
return node;
|
||||
} else {
|
||||
hasExpanded.set(stack.size() - 1);
|
||||
pushIfPresent(stack, rightChild(node));
|
||||
pushIfPresent(stack, leftChild(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(user): see if any significant optimizations are possible for
|
||||
// breadthFirstIterator
|
||||
|
||||
public final FluentIterable<T> inOrderTraversal(final T root) {
|
||||
checkNotNull(root);
|
||||
return new FluentIterable<T>() {
|
||||
@Override
|
||||
public UnmodifiableIterator<T> iterator() {
|
||||
return new InOrderIterator(root);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final class InOrderIterator extends AbstractIterator<T> {
|
||||
private final Deque<T> stack;
|
||||
private final BitSet hasExpandedLeft;
|
||||
|
||||
InOrderIterator(T root) {
|
||||
this.stack = new ArrayDeque<T>();
|
||||
this.hasExpandedLeft = new BitSet();
|
||||
stack.addLast(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T computeNext() {
|
||||
while (!stack.isEmpty()) {
|
||||
T node = stack.getLast();
|
||||
if (hasExpandedLeft.get(stack.size() - 1)) {
|
||||
stack.removeLast();
|
||||
hasExpandedLeft.clear(stack.size());
|
||||
pushIfPresent(stack, rightChild(node));
|
||||
return node;
|
||||
} else {
|
||||
hasExpandedLeft.set(stack.size() - 1);
|
||||
pushIfPresent(stack, leftChild(node));
|
||||
}
|
||||
}
|
||||
return endOfData();
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void pushIfPresent(Deque<T> stack, Optional<T> node) {
|
||||
if (node.isPresent()) {
|
||||
stack.addLast(node.get());
|
||||
}
|
||||
}
|
||||
}
|
55
sources/main/java/com/google/common/collect/BoundType.java
Normal file
55
sources/main/java/com/google/common/collect/BoundType.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Indicates whether an endpoint of some range is contained in the range itself
|
||||
* ("closed") or not ("open"). If a range is unbounded on a side, it is neither
|
||||
* open nor closed on that side; the bound simply does not exist.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
@GwtCompatible
|
||||
public enum BoundType {
|
||||
/**
|
||||
* The endpoint value <i>is not</i> considered part of the set ("exclusive").
|
||||
*/
|
||||
OPEN {
|
||||
@Override
|
||||
BoundType flip() {
|
||||
return CLOSED;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The endpoint value <i>is</i> considered part of the set ("inclusive").
|
||||
*/
|
||||
CLOSED {
|
||||
@Override
|
||||
BoundType flip() {
|
||||
return OPEN;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the bound type corresponding to a boolean value for inclusivity.
|
||||
*/
|
||||
static BoundType forBoolean(boolean inclusive) {
|
||||
return inclusive ? CLOSED : OPEN;
|
||||
}
|
||||
|
||||
abstract BoundType flip();
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* An ordering that orders elements by applying an order to the result of a
|
||||
* function on those elements.
|
||||
*/
|
||||
@GwtCompatible(serializable = true)
|
||||
final class ByFunctionOrdering<F, T> extends Ordering<F> implements Serializable {
|
||||
final Function<F, ? extends T> function;
|
||||
final Ordering<T> ordering;
|
||||
|
||||
ByFunctionOrdering(Function<F, ? extends T> function, Ordering<T> ordering) {
|
||||
this.function = checkNotNull(function);
|
||||
this.ordering = checkNotNull(ordering);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(F left, F right) {
|
||||
return ordering.compare(function.apply(left), function.apply(right));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
if (object == this) {
|
||||
return true;
|
||||
}
|
||||
if (object instanceof ByFunctionOrdering) {
|
||||
ByFunctionOrdering<?, ?> that = (ByFunctionOrdering<?, ?>) object;
|
||||
return this.function.equals(that.function) && this.ordering.equals(that.ordering);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(function, ordering);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ordering + ".onResultOf(" + function + ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
117
sources/main/java/com/google/common/collect/CartesianList.java
Normal file
117
sources/main/java/com/google/common/collect/CartesianList.java
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkElementIndex;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.RandomAccess;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.math.IntMath;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Lists#cartesianProduct(List)}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
final class CartesianList<E> extends AbstractList<List<E>> implements RandomAccess {
|
||||
|
||||
private transient final ImmutableList<List<E>> axes;
|
||||
private transient final int[] axesSizeProduct;
|
||||
|
||||
static <E> List<List<E>> create(List<? extends List<? extends E>> lists) {
|
||||
ImmutableList.Builder<List<E>> axesBuilder = new ImmutableList.Builder<List<E>>(lists.size());
|
||||
for (List<? extends E> list : lists) {
|
||||
List<E> copy = ImmutableList.copyOf(list);
|
||||
if (copy.isEmpty()) {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
axesBuilder.add(copy);
|
||||
}
|
||||
return new CartesianList<E>(axesBuilder.build());
|
||||
}
|
||||
|
||||
CartesianList(ImmutableList<List<E>> axes) {
|
||||
this.axes = axes;
|
||||
int[] axesSizeProduct = new int[axes.size() + 1];
|
||||
axesSizeProduct[axes.size()] = 1;
|
||||
try {
|
||||
for (int i = axes.size() - 1; i >= 0; i--) {
|
||||
axesSizeProduct[i] = IntMath.checkedMultiply(axesSizeProduct[i + 1], axes.get(i).size());
|
||||
}
|
||||
} catch (ArithmeticException e) {
|
||||
throw new IllegalArgumentException("Cartesian product too large; must have size at most Integer.MAX_VALUE");
|
||||
}
|
||||
this.axesSizeProduct = axesSizeProduct;
|
||||
}
|
||||
|
||||
private int getAxisIndexForProductIndex(int index, int axis) {
|
||||
return (index / axesSizeProduct[axis + 1]) % axes.get(axis).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<E> get(final int index) {
|
||||
checkElementIndex(index, size());
|
||||
return new ImmutableList<E>() {
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return axes.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int axis) {
|
||||
checkElementIndex(axis, size());
|
||||
int axisIndex = getAxisIndexForProductIndex(index, axis);
|
||||
return axes.get(axis).get(axisIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return axesSizeProduct[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object o) {
|
||||
if (!(o instanceof List)) {
|
||||
return false;
|
||||
}
|
||||
List<?> list = (List<?>) o;
|
||||
if (list.size() != axes.size()) {
|
||||
return false;
|
||||
}
|
||||
ListIterator<?> itr = list.listIterator();
|
||||
while (itr.hasNext()) {
|
||||
int index = itr.nextIndex();
|
||||
if (!axes.get(index).contains(itr.next())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A map, each entry of which maps a Java
|
||||
* <a href="http://tinyurl.com/2cmwkz">raw type</a> to an instance of that type.
|
||||
* In addition to implementing {@code Map}, the additional type-safe operations
|
||||
* {@link #putInstance} and {@link #getInstance} are available.
|
||||
*
|
||||
* <p>
|
||||
* Like any other {@code Map<Class, Object>}, this map may contain entries for
|
||||
* primitive types, and a primitive type and its corresponding wrapper type may
|
||||
* map to different values.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#ClassToInstanceMap">
|
||||
* {@code ClassToInstanceMap}</a>.
|
||||
*
|
||||
* <p>
|
||||
* To map a generic type to an instance of that type, use
|
||||
* {@link com.google.common.reflect.TypeToInstanceMap} instead.
|
||||
*
|
||||
* @param <B> the common supertype that all entries must share; often this is
|
||||
* simply {@link Object}
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public interface ClassToInstanceMap<B> extends Map<Class<? extends B>, B> {
|
||||
/**
|
||||
* Returns the value the specified class is mapped to, or {@code null} if no
|
||||
* entry for this class is present. This will only return a value that was bound
|
||||
* to this specific class, not a value that may have been bound to a subtype.
|
||||
*/
|
||||
<T extends B> T getInstance(Class<T> type);
|
||||
|
||||
/**
|
||||
* Maps the specified class to the specified value. Does <i>not</i> associate
|
||||
* this value with any of the class's supertypes.
|
||||
*
|
||||
* @return the value previously associated with this class (possibly {@code
|
||||
* null}), or {@code null} if there was no previous entry.
|
||||
*/
|
||||
<T extends B> T putInstance(Class<T> type, @Nullable T value);
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Precondition checks useful in collection implementations.
|
||||
*/
|
||||
@GwtCompatible
|
||||
final class CollectPreconditions {
|
||||
|
||||
static void checkEntryNotNull(Object key, Object value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("null key in entry: null=" + value);
|
||||
} else if (value == null) {
|
||||
throw new NullPointerException("null value in entry: " + key + "=null");
|
||||
}
|
||||
}
|
||||
|
||||
static int checkNonnegative(int value, String name) {
|
||||
if (value < 0) {
|
||||
throw new IllegalArgumentException(name + " cannot be negative but was: " + value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Precondition tester for {@code Iterator.remove()} that throws an exception
|
||||
* with a consistent error message.
|
||||
*/
|
||||
static void checkRemove(boolean canRemove) {
|
||||
checkState(canRemove, "no calls to next() since the last call to remove()");
|
||||
}
|
||||
}
|
695
sources/main/java/com/google/common/collect/Collections2.java
Normal file
695
sources/main/java/com/google/common/collect/Collections2.java
Normal file
@ -0,0 +1,695 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Predicates.and;
|
||||
import static com.google.common.base.Predicates.in;
|
||||
import static com.google.common.base.Predicates.not;
|
||||
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
|
||||
import static com.google.common.math.LongMath.binomial;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.math.IntMath;
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
/**
|
||||
* Provides static methods for working with {@code Collection} instances.
|
||||
*
|
||||
* @author Chris Povirk
|
||||
* @author Mike Bostock
|
||||
* @author Jared Levy
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public final class Collections2 {
|
||||
private Collections2() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the elements of {@code unfiltered} that satisfy a predicate. The
|
||||
* returned collection is a live view of {@code unfiltered}; changes to one
|
||||
* affect the other.
|
||||
*
|
||||
* <p>
|
||||
* The resulting collection's iterator does not support {@code remove()}, but
|
||||
* all other collection methods are supported. When given an element that
|
||||
* doesn't satisfy the predicate, the collection's {@code add()} and {@code
|
||||
* addAll()} methods throw an {@link IllegalArgumentException}. When methods
|
||||
* such as {@code removeAll()} and {@code clear()} are called on the filtered
|
||||
* collection, only elements that satisfy the filter will be removed from the
|
||||
* underlying collection.
|
||||
*
|
||||
* <p>
|
||||
* The returned collection isn't threadsafe or serializable, even if
|
||||
* {@code unfiltered} is.
|
||||
*
|
||||
* <p>
|
||||
* Many of the filtered collection's methods, such as {@code size()}, iterate
|
||||
* across every element in the underlying collection and determine which
|
||||
* elements satisfy the filter. When a live view is <i>not</i> needed, it may be
|
||||
* faster to copy {@code Iterables.filter(unfiltered, predicate)} and use the
|
||||
* copy.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>, as
|
||||
* documented at {@link Predicate#apply}. Do not provide a predicate such as
|
||||
* {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent with
|
||||
* equals. (See {@link Iterables#filter(Iterable, Class)} for related
|
||||
* functionality.)
|
||||
*/
|
||||
// TODO(kevinb): how can we omit that Iterables link when building gwt
|
||||
// javadoc?
|
||||
public static <E> Collection<E> filter(Collection<E> unfiltered, Predicate<? super E> predicate) {
|
||||
if (unfiltered instanceof FilteredCollection) {
|
||||
// Support clear(), removeAll(), and retainAll() when filtering a filtered
|
||||
// collection.
|
||||
return ((FilteredCollection<E>) unfiltered).createCombined(predicate);
|
||||
}
|
||||
|
||||
return new FilteredCollection<E>(checkNotNull(unfiltered), checkNotNull(predicate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Collection#contains}. Returns {@code false} if the
|
||||
* {@code contains} method throws a {@code ClassCastException} or
|
||||
* {@code NullPointerException}.
|
||||
*/
|
||||
static boolean safeContains(Collection<?> collection, @Nullable Object object) {
|
||||
checkNotNull(collection);
|
||||
try {
|
||||
return collection.contains(object);
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to {@link Collection#remove}. Returns {@code false} if the
|
||||
* {@code remove} method throws a {@code ClassCastException} or
|
||||
* {@code NullPointerException}.
|
||||
*/
|
||||
static boolean safeRemove(Collection<?> collection, @Nullable Object object) {
|
||||
checkNotNull(collection);
|
||||
try {
|
||||
return collection.remove(object);
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static class FilteredCollection<E> extends AbstractCollection<E> {
|
||||
final Collection<E> unfiltered;
|
||||
final Predicate<? super E> predicate;
|
||||
|
||||
FilteredCollection(Collection<E> unfiltered, Predicate<? super E> predicate) {
|
||||
this.unfiltered = unfiltered;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
FilteredCollection<E> createCombined(Predicate<? super E> newPredicate) {
|
||||
return new FilteredCollection<E>(unfiltered, Predicates.<E>and(predicate, newPredicate));
|
||||
// .<E> above needed to compile in JDK 5
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
checkArgument(predicate.apply(element));
|
||||
return unfiltered.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> collection) {
|
||||
for (E element : collection) {
|
||||
checkArgument(predicate.apply(element));
|
||||
}
|
||||
return unfiltered.addAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
Iterables.removeIf(unfiltered, predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object element) {
|
||||
if (safeContains(unfiltered, element)) {
|
||||
@SuppressWarnings("unchecked") // element is in unfiltered, so it must be an E
|
||||
E e = (E) element;
|
||||
return predicate.apply(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> collection) {
|
||||
return containsAllImpl(this, collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return !Iterables.any(unfiltered, predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Iterators.filter(unfiltered.iterator(), predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object element) {
|
||||
return contains(element) && unfiltered.remove(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(final Collection<?> collection) {
|
||||
return Iterables.removeIf(unfiltered, and(predicate, (Predicate<E>)in(collection)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(final Collection<?> collection) {
|
||||
return Iterables.removeIf(unfiltered, and(predicate, (Predicate<E>)not(in(collection))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Iterators.size(iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
// creating an ArrayList so filtering happens once
|
||||
return Lists.newArrayList(iterator()).toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return Lists.newArrayList(iterator()).toArray(array);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection that applies {@code function} to each element of
|
||||
* {@code fromCollection}. The returned collection is a live view of {@code
|
||||
* fromCollection}; changes to one affect the other.
|
||||
*
|
||||
* <p>
|
||||
* The returned collection's {@code add()} and {@code addAll()} methods throw an
|
||||
* {@link UnsupportedOperationException}. All other collection methods are
|
||||
* supported, as long as {@code fromCollection} supports them.
|
||||
*
|
||||
* <p>
|
||||
* The returned collection isn't threadsafe or serializable, even if
|
||||
* {@code fromCollection} is.
|
||||
*
|
||||
* <p>
|
||||
* When a live view is <i>not</i> needed, it may be faster to copy the
|
||||
* transformed collection and use the copy.
|
||||
*
|
||||
* <p>
|
||||
* If the input {@code Collection} is known to be a {@code List}, consider
|
||||
* {@link Lists#transform}. If only an {@code Iterable} is available, use
|
||||
* {@link Iterables#transform}.
|
||||
*/
|
||||
public static <F, T> Collection<T> transform(Collection<F> fromCollection, Function<? super F, T> function) {
|
||||
return new TransformedCollection<F, T>(fromCollection, function);
|
||||
}
|
||||
|
||||
static class TransformedCollection<F, T> extends AbstractCollection<T> {
|
||||
final Collection<F> fromCollection;
|
||||
final Function<? super F, ? extends T> function;
|
||||
|
||||
TransformedCollection(Collection<F> fromCollection, Function<? super F, ? extends T> function) {
|
||||
this.fromCollection = checkNotNull(fromCollection);
|
||||
this.function = checkNotNull(function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
fromCollection.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return fromCollection.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return Iterators.transform(fromCollection.iterator(), function);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return fromCollection.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the collection {@code self} contains all of the
|
||||
* elements in the collection {@code c}.
|
||||
*
|
||||
* <p>
|
||||
* This method iterates over the specified collection {@code c}, checking each
|
||||
* element returned by the iterator in turn to see if it is contained in the
|
||||
* specified collection {@code self}. If all elements are so contained,
|
||||
* {@code true} is returned, otherwise {@code false}.
|
||||
*
|
||||
* @param self a collection which might contain all elements in {@code c}
|
||||
* @param c a collection whose elements might be contained by {@code self}
|
||||
*/
|
||||
static boolean containsAllImpl(Collection<?> self, Collection<?> c) {
|
||||
return Iterables.all(c, Predicates.in(self));
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of {@link Collection#toString()}.
|
||||
*/
|
||||
static String toStringImpl(final Collection<?> collection) {
|
||||
StringBuilder sb = newStringBuilderForCollection(collection.size()).append('[');
|
||||
STANDARD_JOINER.appendTo(sb, Iterables.transform(collection, new Function<Object, Object>() {
|
||||
@Override
|
||||
public Object apply(Object input) {
|
||||
return input == collection ? "(this Collection)" : input;
|
||||
}
|
||||
}));
|
||||
return sb.append(']').toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns best-effort-sized StringBuilder based on the given collection size.
|
||||
*/
|
||||
static StringBuilder newStringBuilderForCollection(int size) {
|
||||
checkNonnegative(size, "size");
|
||||
return new StringBuilder((int) Math.min(size * 8L, Ints.MAX_POWER_OF_TWO));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
|
||||
*/
|
||||
static <T> Collection<T> cast(Iterable<T> iterable) {
|
||||
return (Collection<T>) iterable;
|
||||
}
|
||||
|
||||
static final Joiner STANDARD_JOINER = Joiner.on(", ").useForNull("null");
|
||||
|
||||
/**
|
||||
* Returns a {@link Collection} of all the permutations of the specified
|
||||
* {@link Iterable}.
|
||||
*
|
||||
* <p>
|
||||
* <i>Notes:</i> This is an implementation of the algorithm for Lexicographical
|
||||
* Permutations Generation, described in Knuth's "The Art of Computer
|
||||
* Programming", Volume 4, Chapter 7, Section 7.2.1.2. The iteration order
|
||||
* follows the lexicographical order. This means that the first permutation will
|
||||
* be in ascending order, and the last will be in descending order.
|
||||
*
|
||||
* <p>
|
||||
* Duplicate elements are considered equal. For example, the list [1, 1] will
|
||||
* have only one permutation, instead of two. This is why the elements have to
|
||||
* implement {@link Comparable}.
|
||||
*
|
||||
* <p>
|
||||
* An empty iterable has only one permutation, which is an empty list.
|
||||
*
|
||||
* <p>
|
||||
* This method is equivalent to
|
||||
* {@code Collections2.orderedPermutations(list, Ordering.natural())}.
|
||||
*
|
||||
* @param elements the original iterable whose elements have to be permuted.
|
||||
* @return an immutable {@link Collection} containing all the different
|
||||
* permutations of the original iterable.
|
||||
* @throws NullPointerException if the specified iterable is null or has any
|
||||
* null elements.
|
||||
* @since 12.0
|
||||
*/
|
||||
@Beta
|
||||
public static <E extends Comparable<? super E>> Collection<List<E>> orderedPermutations(Iterable<E> elements) {
|
||||
return orderedPermutations(elements, Ordering.natural());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Collection} of all the permutations of the specified
|
||||
* {@link Iterable} using the specified {@link Comparator} for establishing the
|
||||
* lexicographical ordering.
|
||||
*
|
||||
* <p>
|
||||
* Examples:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
*
|
||||
* for (List<String> perm : orderedPermutations(asList("b", "c", "a"))) {
|
||||
* println(perm);
|
||||
* }
|
||||
* // -> ["a", "b", "c"]
|
||||
* // -> ["a", "c", "b"]
|
||||
* // -> ["b", "a", "c"]
|
||||
* // -> ["b", "c", "a"]
|
||||
* // -> ["c", "a", "b"]
|
||||
* // -> ["c", "b", "a"]
|
||||
*
|
||||
* for (List<Integer> perm : orderedPermutations(asList(1, 2, 2, 1))) {
|
||||
* println(perm);
|
||||
* }
|
||||
* // -> [1, 1, 2, 2]
|
||||
* // -> [1, 2, 1, 2]
|
||||
* // -> [1, 2, 2, 1]
|
||||
* // -> [2, 1, 1, 2]
|
||||
* // -> [2, 1, 2, 1]
|
||||
* // -> [2, 2, 1, 1]}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <i>Notes:</i> This is an implementation of the algorithm for Lexicographical
|
||||
* Permutations Generation, described in Knuth's "The Art of Computer
|
||||
* Programming", Volume 4, Chapter 7, Section 7.2.1.2. The iteration order
|
||||
* follows the lexicographical order. This means that the first permutation will
|
||||
* be in ascending order, and the last will be in descending order.
|
||||
*
|
||||
* <p>
|
||||
* Elements that compare equal are considered equal and no new permutations are
|
||||
* created by swapping them.
|
||||
*
|
||||
* <p>
|
||||
* An empty iterable has only one permutation, which is an empty list.
|
||||
*
|
||||
* @param elements the original iterable whose elements have to be permuted.
|
||||
* @param comparator a comparator for the iterable's elements.
|
||||
* @return an immutable {@link Collection} containing all the different
|
||||
* permutations of the original iterable.
|
||||
* @throws NullPointerException If the specified iterable is null, has any null
|
||||
* elements, or if the specified comparator is
|
||||
* null.
|
||||
* @since 12.0
|
||||
*/
|
||||
@Beta
|
||||
public static <E> Collection<List<E>> orderedPermutations(Iterable<E> elements, Comparator<? super E> comparator) {
|
||||
return new OrderedPermutationCollection<E>(elements, comparator);
|
||||
}
|
||||
|
||||
private static final class OrderedPermutationCollection<E> extends AbstractCollection<List<E>> {
|
||||
final ImmutableList<E> inputList;
|
||||
final Comparator<? super E> comparator;
|
||||
final int size;
|
||||
|
||||
OrderedPermutationCollection(Iterable<E> input, Comparator<? super E> comparator) {
|
||||
this.inputList = Ordering.from(comparator).immutableSortedCopy(input);
|
||||
this.comparator = comparator;
|
||||
this.size = calculateSize(inputList, comparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of permutations with repeated elements is calculated as follows:
|
||||
* <ul>
|
||||
* <li>For an empty list, it is 1 (base case).</li>
|
||||
* <li>When r numbers are added to a list of n-r elements, the number of
|
||||
* permutations is increased by a factor of (n choose r).</li>
|
||||
* </ul>
|
||||
*/
|
||||
private static <E> int calculateSize(List<E> sortedInputList, Comparator<? super E> comparator) {
|
||||
long permutations = 1;
|
||||
int n = 1;
|
||||
int r = 1;
|
||||
while (n < sortedInputList.size()) {
|
||||
int comparison = comparator.compare(sortedInputList.get(n - 1), sortedInputList.get(n));
|
||||
if (comparison < 0) {
|
||||
// We move to the next non-repeated element.
|
||||
permutations *= binomial(n, r);
|
||||
r = 0;
|
||||
if (!isPositiveInt(permutations)) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
n++;
|
||||
r++;
|
||||
}
|
||||
permutations *= binomial(n, r);
|
||||
if (!isPositiveInt(permutations)) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
return (int) permutations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<List<E>> iterator() {
|
||||
return new OrderedPermutationIterator<E>(inputList, comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object obj) {
|
||||
if (obj instanceof List) {
|
||||
List<?> list = (List<?>) obj;
|
||||
return isPermutation(inputList, list);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "orderedPermutationCollection(" + inputList + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class OrderedPermutationIterator<E> extends AbstractIterator<List<E>> {
|
||||
|
||||
List<E> nextPermutation;
|
||||
final Comparator<? super E> comparator;
|
||||
|
||||
OrderedPermutationIterator(List<E> list, Comparator<? super E> comparator) {
|
||||
this.nextPermutation = Lists.newArrayList(list);
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<E> computeNext() {
|
||||
if (nextPermutation == null) {
|
||||
return endOfData();
|
||||
}
|
||||
ImmutableList<E> next = ImmutableList.copyOf(nextPermutation);
|
||||
calculateNextPermutation();
|
||||
return next;
|
||||
}
|
||||
|
||||
void calculateNextPermutation() {
|
||||
int j = findNextJ();
|
||||
if (j == -1) {
|
||||
nextPermutation = null;
|
||||
return;
|
||||
}
|
||||
|
||||
int l = findNextL(j);
|
||||
Collections.swap(nextPermutation, j, l);
|
||||
int n = nextPermutation.size();
|
||||
Collections.reverse(nextPermutation.subList(j + 1, n));
|
||||
}
|
||||
|
||||
int findNextJ() {
|
||||
for (int k = nextPermutation.size() - 2; k >= 0; k--) {
|
||||
if (comparator.compare(nextPermutation.get(k), nextPermutation.get(k + 1)) < 0) {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int findNextL(int j) {
|
||||
E ak = nextPermutation.get(j);
|
||||
for (int l = nextPermutation.size() - 1; l > j; l--) {
|
||||
if (comparator.compare(ak, nextPermutation.get(l)) < 0) {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
throw new AssertionError("this statement should be unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Collection} of all the permutations of the specified
|
||||
* {@link Collection}.
|
||||
*
|
||||
* <p>
|
||||
* <i>Notes:</i> This is an implementation of the Plain Changes algorithm for
|
||||
* permutations generation, described in Knuth's "The Art of Computer
|
||||
* Programming", Volume 4, Chapter 7, Section 7.2.1.2.
|
||||
*
|
||||
* <p>
|
||||
* If the input list contains equal elements, some of the generated permutations
|
||||
* will be equal.
|
||||
*
|
||||
* <p>
|
||||
* An empty collection has only one permutation, which is an empty list.
|
||||
*
|
||||
* @param elements the original collection whose elements have to be permuted.
|
||||
* @return an immutable {@link Collection} containing all the different
|
||||
* permutations of the original collection.
|
||||
* @throws NullPointerException if the specified collection is null or has any
|
||||
* null elements.
|
||||
* @since 12.0
|
||||
*/
|
||||
@Beta
|
||||
public static <E> Collection<List<E>> permutations(Collection<E> elements) {
|
||||
return new PermutationCollection<E>(ImmutableList.copyOf(elements));
|
||||
}
|
||||
|
||||
private static final class PermutationCollection<E> extends AbstractCollection<List<E>> {
|
||||
final ImmutableList<E> inputList;
|
||||
|
||||
PermutationCollection(ImmutableList<E> input) {
|
||||
this.inputList = input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return IntMath.factorial(inputList.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<List<E>> iterator() {
|
||||
return new PermutationIterator<E>(inputList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object obj) {
|
||||
if (obj instanceof List) {
|
||||
List<?> list = (List<?>) obj;
|
||||
return isPermutation(inputList, list);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "permutations(" + inputList + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static class PermutationIterator<E> extends AbstractIterator<List<E>> {
|
||||
final List<E> list;
|
||||
final int[] c;
|
||||
final int[] o;
|
||||
int j;
|
||||
|
||||
PermutationIterator(List<E> list) {
|
||||
this.list = new ArrayList<E>(list);
|
||||
int n = list.size();
|
||||
c = new int[n];
|
||||
o = new int[n];
|
||||
Arrays.fill(c, 0);
|
||||
Arrays.fill(o, 1);
|
||||
j = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<E> computeNext() {
|
||||
if (j <= 0) {
|
||||
return endOfData();
|
||||
}
|
||||
ImmutableList<E> next = ImmutableList.copyOf(list);
|
||||
calculateNextPermutation();
|
||||
return next;
|
||||
}
|
||||
|
||||
void calculateNextPermutation() {
|
||||
j = list.size() - 1;
|
||||
int s = 0;
|
||||
|
||||
// Handle the special case of an empty list. Skip the calculation of the
|
||||
// next permutation.
|
||||
if (j == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
int q = c[j] + o[j];
|
||||
if (q < 0) {
|
||||
switchDirection();
|
||||
continue;
|
||||
}
|
||||
if (q == j + 1) {
|
||||
if (j == 0) {
|
||||
break;
|
||||
}
|
||||
s++;
|
||||
switchDirection();
|
||||
continue;
|
||||
}
|
||||
|
||||
Collections.swap(list, j - c[j] + s, j - q + s);
|
||||
c[j] = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void switchDirection() {
|
||||
o[j] = -o[j];
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the second list is a permutation of the first.
|
||||
*/
|
||||
private static boolean isPermutation(List<?> first, List<?> second) {
|
||||
if (first.size() != second.size()) {
|
||||
return false;
|
||||
}
|
||||
Multiset<?> firstMultiset = HashMultiset.create(first);
|
||||
Multiset<?> secondMultiset = HashMultiset.create(second);
|
||||
return firstMultiset.equals(secondMultiset);
|
||||
}
|
||||
|
||||
private static boolean isPositiveInt(long n) {
|
||||
return n >= 0 && n <= Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/** An ordering for a pre-existing comparator. */
|
||||
@GwtCompatible(serializable = true)
|
||||
final class ComparatorOrdering<T> extends Ordering<T> implements Serializable {
|
||||
final Comparator<T> comparator;
|
||||
|
||||
ComparatorOrdering(Comparator<T> comparator) {
|
||||
this.comparator = checkNotNull(comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(T a, T b) {
|
||||
return comparator.compare(a, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
if (object == this) {
|
||||
return true;
|
||||
}
|
||||
if (object instanceof ComparatorOrdering) {
|
||||
ComparatorOrdering<?> that = (ComparatorOrdering<?>) object;
|
||||
return this.comparator.equals(that.comparator);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return comparator.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return comparator.toString();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
253
sources/main/java/com/google/common/collect/ComparisonChain.java
Normal file
253
sources/main/java/com/google/common/collect/ComparisonChain.java
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.primitives.Booleans;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.google.common.primitives.Longs;
|
||||
|
||||
/**
|
||||
* A utility for performing a chained comparison statement. For example:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
*
|
||||
* public int compareTo(Foo that) {
|
||||
* return ComparisonChain.start()
|
||||
* .compare(this.aString, that.aString)
|
||||
* .compare(this.anInt, that.anInt)
|
||||
* .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
|
||||
* .result();
|
||||
* }}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* The value of this expression will have the same sign as the <i>first
|
||||
* nonzero</i> comparison result in the chain, or will be zero if every
|
||||
* comparison result was zero.
|
||||
*
|
||||
* <p>
|
||||
* Performance note: Even though the {@code ComparisonChain} caller always
|
||||
* invokes its {@code compare} methods unconditionally, the {@code
|
||||
* ComparisonChain} implementation stops calling its inputs'
|
||||
* {@link Comparable#compareTo compareTo} and {@link Comparator#compare compare}
|
||||
* methods as soon as one of them returns a nonzero result. This optimization is
|
||||
* typically important only in the presence of expensive {@code compareTo} and
|
||||
* {@code compare} implementations.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained#compare/compareTo">
|
||||
* {@code ComparisonChain}</a>.
|
||||
*
|
||||
* @author Mark Davis
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ComparisonChain {
|
||||
private ComparisonChain() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a new chained comparison statement. See example in the class
|
||||
* documentation.
|
||||
*/
|
||||
public static ComparisonChain start() {
|
||||
return ACTIVE;
|
||||
}
|
||||
|
||||
private static final ComparisonChain ACTIVE = new ComparisonChain() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ComparisonChain compare(Comparable left, Comparable right) {
|
||||
return classify(left.compareTo(right));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ComparisonChain compare(@Nullable T left, @Nullable T right, Comparator<T> comparator) {
|
||||
return classify(comparator.compare(left, right));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compare(int left, int right) {
|
||||
return classify(Ints.compare(left, right));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compare(long left, long right) {
|
||||
return classify(Longs.compare(left, right));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compare(float left, float right) {
|
||||
return classify(Float.compare(left, right));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compare(double left, double right) {
|
||||
return classify(Double.compare(left, right));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compareTrueFirst(boolean left, boolean right) {
|
||||
return classify(Booleans.compare(right, left)); // reversed
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compareFalseFirst(boolean left, boolean right) {
|
||||
return classify(Booleans.compare(left, right));
|
||||
}
|
||||
|
||||
ComparisonChain classify(int result) {
|
||||
return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int result() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
|
||||
|
||||
private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
|
||||
|
||||
private static final class InactiveComparisonChain extends ComparisonChain {
|
||||
final int result;
|
||||
|
||||
InactiveComparisonChain(int result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compare(@Nullable Comparable left, @Nullable Comparable right) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ComparisonChain compare(@Nullable T left, @Nullable T right, @Nullable Comparator<T> comparator) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compare(int left, int right) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compare(long left, long right) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compare(float left, float right) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compare(double left, double right) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compareTrueFirst(boolean left, boolean right) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComparisonChain compareFalseFirst(boolean left, boolean right) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int result() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two comparable objects as specified by {@link Comparable#compareTo},
|
||||
* <i>if</i> the result of this comparison chain has not already been
|
||||
* determined.
|
||||
*/
|
||||
public abstract ComparisonChain compare(Comparable<?> left, Comparable<?> right);
|
||||
|
||||
/**
|
||||
* Compares two objects using a comparator, <i>if</i> the result of this
|
||||
* comparison chain has not already been determined.
|
||||
*/
|
||||
public abstract <T> ComparisonChain compare(@Nullable T left, @Nullable T right, Comparator<T> comparator);
|
||||
|
||||
/**
|
||||
* Compares two {@code int} values as specified by {@link Ints#compare},
|
||||
* <i>if</i> the result of this comparison chain has not already been
|
||||
* determined.
|
||||
*/
|
||||
public abstract ComparisonChain compare(int left, int right);
|
||||
|
||||
/**
|
||||
* Compares two {@code long} values as specified by {@link Longs#compare},
|
||||
* <i>if</i> the result of this comparison chain has not already been
|
||||
* determined.
|
||||
*/
|
||||
public abstract ComparisonChain compare(long left, long right);
|
||||
|
||||
/**
|
||||
* Compares two {@code float} values as specified by {@link Float#compare},
|
||||
* <i>if</i> the result of this comparison chain has not already been
|
||||
* determined.
|
||||
*/
|
||||
public abstract ComparisonChain compare(float left, float right);
|
||||
|
||||
/**
|
||||
* Compares two {@code double} values as specified by {@link Double#compare},
|
||||
* <i>if</i> the result of this comparison chain has not already been
|
||||
* determined.
|
||||
*/
|
||||
public abstract ComparisonChain compare(double left, double right);
|
||||
|
||||
/**
|
||||
* Compares two {@code boolean} values, considering {@code true} to be less than
|
||||
* {@code false}, <i>if</i> the result of this comparison chain has not already
|
||||
* been determined.
|
||||
*
|
||||
* @since 12.0
|
||||
*/
|
||||
public abstract ComparisonChain compareTrueFirst(boolean left, boolean right);
|
||||
|
||||
/**
|
||||
* Compares two {@code boolean} values, considering {@code false} to be less
|
||||
* than {@code true}, <i>if</i> the result of this comparison chain has not
|
||||
* already been determined.
|
||||
*
|
||||
* @since 12.0 (present as {@code compare} since 2.0)
|
||||
*/
|
||||
public abstract ComparisonChain compareFalseFirst(boolean left, boolean right);
|
||||
|
||||
/**
|
||||
* Ends this comparison chain and returns its result: a value having the same
|
||||
* sign as the first nonzero comparison result in the chain, or zero if every
|
||||
* result was zero.
|
||||
*/
|
||||
public abstract int result();
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/** An ordering that tries several comparators in order. */
|
||||
@GwtCompatible(serializable = true)
|
||||
final class CompoundOrdering<T> extends Ordering<T> implements Serializable {
|
||||
final ImmutableList<Comparator<? super T>> comparators;
|
||||
|
||||
CompoundOrdering(Comparator<? super T> primary, Comparator<? super T> secondary) {
|
||||
this.comparators = ImmutableList.<Comparator<? super T>>of(primary, secondary);
|
||||
}
|
||||
|
||||
CompoundOrdering(Iterable<? extends Comparator<? super T>> comparators) {
|
||||
this.comparators = ImmutableList.copyOf(comparators);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(T left, T right) {
|
||||
// Avoid using the Iterator to avoid generating garbage (issue 979).
|
||||
int size = comparators.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int result = comparators.get(i).compare(left, right);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (object == this) {
|
||||
return true;
|
||||
}
|
||||
if (object instanceof CompoundOrdering) {
|
||||
CompoundOrdering<?> that = (CompoundOrdering<?>) object;
|
||||
return this.comparators.equals(that.comparators);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return comparators.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Ordering.compound(" + comparators + ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Wraps an exception that occurred during a computation.
|
||||
*
|
||||
* @author Bob Lee
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public class ComputationException extends RuntimeException {
|
||||
/**
|
||||
* Creates a new instance with the given cause.
|
||||
*/
|
||||
public ComputationException(@Nullable Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
66
sources/main/java/com/google/common/collect/Constraint.java
Normal file
66
sources/main/java/com/google/common/collect/Constraint.java
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A constraint that an element must satisfy in order to be added to a
|
||||
* collection. For example, {@link Constraints#notNull()}, which prevents a
|
||||
* collection from including any null elements, could be implemented like this:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
*
|
||||
* public Object checkElement(Object element) {
|
||||
* if (element == null) {
|
||||
* throw new NullPointerException();
|
||||
* }
|
||||
* return element;
|
||||
* }}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* In order to be effective, constraints should be deterministic; that is, they
|
||||
* should not depend on state that can change (such as external state, random
|
||||
* variables, and time) and should only depend on the value of the passed-in
|
||||
* element. A non-deterministic constraint cannot reliably enforce that all the
|
||||
* collection's elements meet the constraint, since the constraint is only
|
||||
* enforced when elements are added.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
*/
|
||||
@GwtCompatible
|
||||
interface Constraint<E> {
|
||||
/**
|
||||
* Throws a suitable {@code RuntimeException} if the specified element is
|
||||
* illegal. Typically this is either a {@link NullPointerException}, an
|
||||
* {@link IllegalArgumentException}, or a {@link ClassCastException}, though an
|
||||
* application-specific exception class may be used if appropriate.
|
||||
*
|
||||
* @param element the element to check
|
||||
* @return the provided element
|
||||
*/
|
||||
E checkElement(E element);
|
||||
|
||||
/**
|
||||
* Returns a brief human readable description of this constraint, such as "Not
|
||||
* null" or "Positive number".
|
||||
*/
|
||||
@Override
|
||||
String toString();
|
||||
}
|
340
sources/main/java/com/google/common/collect/Constraints.java
Normal file
340
sources/main/java/com/google/common/collect/Constraints.java
Normal file
@ -0,0 +1,340 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.RandomAccess;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Factories and utilities pertaining to the {@link Constraint} interface.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @author Jared Levy
|
||||
*/
|
||||
@GwtCompatible
|
||||
final class Constraints {
|
||||
private Constraints() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a constrained view of the specified collection, using the specified
|
||||
* constraint. Any operations that add new elements to the collection will call
|
||||
* the provided constraint. However, this method does not verify that existing
|
||||
* elements satisfy the constraint.
|
||||
*
|
||||
* <p>
|
||||
* The returned collection is not serializable.
|
||||
*
|
||||
* @param collection the collection to constrain
|
||||
* @param constraint the constraint that validates added elements
|
||||
* @return a constrained view of the collection
|
||||
*/
|
||||
public static <E> Collection<E> constrainedCollection(Collection<E> collection, Constraint<? super E> constraint) {
|
||||
return new ConstrainedCollection<E>(collection, constraint);
|
||||
}
|
||||
|
||||
/** @see Constraints#constrainedCollection */
|
||||
static class ConstrainedCollection<E> extends ForwardingCollection<E> {
|
||||
private final Collection<E> delegate;
|
||||
private final Constraint<? super E> constraint;
|
||||
|
||||
public ConstrainedCollection(Collection<E> delegate, Constraint<? super E> constraint) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
this.constraint = checkNotNull(constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<E> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
constraint.checkElement(element);
|
||||
return delegate.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> elements) {
|
||||
return delegate.addAll(checkElements(elements, constraint));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a constrained view of the specified set, using the specified
|
||||
* constraint. Any operations that add new elements to the set will call the
|
||||
* provided constraint. However, this method does not verify that existing
|
||||
* elements satisfy the constraint.
|
||||
*
|
||||
* <p>
|
||||
* The returned set is not serializable.
|
||||
*
|
||||
* @param set the set to constrain
|
||||
* @param constraint the constraint that validates added elements
|
||||
* @return a constrained view of the set
|
||||
*/
|
||||
public static <E> Set<E> constrainedSet(Set<E> set, Constraint<? super E> constraint) {
|
||||
return new ConstrainedSet<E>(set, constraint);
|
||||
}
|
||||
|
||||
/** @see Constraints#constrainedSet */
|
||||
static class ConstrainedSet<E> extends ForwardingSet<E> {
|
||||
private final Set<E> delegate;
|
||||
private final Constraint<? super E> constraint;
|
||||
|
||||
public ConstrainedSet(Set<E> delegate, Constraint<? super E> constraint) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
this.constraint = checkNotNull(constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<E> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
constraint.checkElement(element);
|
||||
return delegate.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> elements) {
|
||||
return delegate.addAll(checkElements(elements, constraint));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a constrained view of the specified sorted set, using the specified
|
||||
* constraint. Any operations that add new elements to the sorted set will call
|
||||
* the provided constraint. However, this method does not verify that existing
|
||||
* elements satisfy the constraint.
|
||||
*
|
||||
* <p>
|
||||
* The returned set is not serializable.
|
||||
*
|
||||
* @param sortedSet the sorted set to constrain
|
||||
* @param constraint the constraint that validates added elements
|
||||
* @return a constrained view of the sorted set
|
||||
*/
|
||||
public static <E> SortedSet<E> constrainedSortedSet(SortedSet<E> sortedSet, Constraint<? super E> constraint) {
|
||||
return new ConstrainedSortedSet<E>(sortedSet, constraint);
|
||||
}
|
||||
|
||||
/** @see Constraints#constrainedSortedSet */
|
||||
private static class ConstrainedSortedSet<E> extends ForwardingSortedSet<E> {
|
||||
final SortedSet<E> delegate;
|
||||
final Constraint<? super E> constraint;
|
||||
|
||||
ConstrainedSortedSet(SortedSet<E> delegate, Constraint<? super E> constraint) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
this.constraint = checkNotNull(constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SortedSet<E> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> headSet(E toElement) {
|
||||
return constrainedSortedSet(delegate.headSet(toElement), constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> subSet(E fromElement, E toElement) {
|
||||
return constrainedSortedSet(delegate.subSet(fromElement, toElement), constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> tailSet(E fromElement) {
|
||||
return constrainedSortedSet(delegate.tailSet(fromElement), constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
constraint.checkElement(element);
|
||||
return delegate.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> elements) {
|
||||
return delegate.addAll(checkElements(elements, constraint));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a constrained view of the specified list, using the specified
|
||||
* constraint. Any operations that add new elements to the list will call the
|
||||
* provided constraint. However, this method does not verify that existing
|
||||
* elements satisfy the constraint.
|
||||
*
|
||||
* <p>
|
||||
* If {@code list} implements {@link RandomAccess}, so will the returned list.
|
||||
* The returned list is not serializable.
|
||||
*
|
||||
* @param list the list to constrain
|
||||
* @param constraint the constraint that validates added elements
|
||||
* @return a constrained view of the list
|
||||
*/
|
||||
public static <E> List<E> constrainedList(List<E> list, Constraint<? super E> constraint) {
|
||||
return (list instanceof RandomAccess) ? new ConstrainedRandomAccessList<E>(list, constraint)
|
||||
: new ConstrainedList<E>(list, constraint);
|
||||
}
|
||||
|
||||
/** @see Constraints#constrainedList */
|
||||
@GwtCompatible
|
||||
private static class ConstrainedList<E> extends ForwardingList<E> {
|
||||
final List<E> delegate;
|
||||
final Constraint<? super E> constraint;
|
||||
|
||||
ConstrainedList(List<E> delegate, Constraint<? super E> constraint) {
|
||||
this.delegate = checkNotNull(delegate);
|
||||
this.constraint = checkNotNull(constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<E> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
constraint.checkElement(element);
|
||||
return delegate.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
constraint.checkElement(element);
|
||||
delegate.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> elements) {
|
||||
return delegate.addAll(checkElements(elements, constraint));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends E> elements) {
|
||||
return delegate.addAll(index, checkElements(elements, constraint));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<E> listIterator() {
|
||||
return constrainedListIterator(delegate.listIterator(), constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
return constrainedListIterator(delegate.listIterator(index), constraint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
constraint.checkElement(element);
|
||||
return delegate.set(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
return constrainedList(delegate.subList(fromIndex, toIndex), constraint);
|
||||
}
|
||||
}
|
||||
|
||||
/** @see Constraints#constrainedList */
|
||||
static class ConstrainedRandomAccessList<E> extends ConstrainedList<E> implements RandomAccess {
|
||||
ConstrainedRandomAccessList(List<E> delegate, Constraint<? super E> constraint) {
|
||||
super(delegate, constraint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a constrained view of the specified list iterator, using the
|
||||
* specified constraint. Any operations that would add new elements to the
|
||||
* underlying list will be verified by the constraint.
|
||||
*
|
||||
* @param listIterator the iterator for which to return a constrained view
|
||||
* @param constraint the constraint for elements in the list
|
||||
* @return a constrained view of the specified iterator
|
||||
*/
|
||||
private static <E> ListIterator<E> constrainedListIterator(ListIterator<E> listIterator,
|
||||
Constraint<? super E> constraint) {
|
||||
return new ConstrainedListIterator<E>(listIterator, constraint);
|
||||
}
|
||||
|
||||
/** @see Constraints#constrainedListIterator */
|
||||
static class ConstrainedListIterator<E> extends ForwardingListIterator<E> {
|
||||
private final ListIterator<E> delegate;
|
||||
private final Constraint<? super E> constraint;
|
||||
|
||||
public ConstrainedListIterator(ListIterator<E> delegate, Constraint<? super E> constraint) {
|
||||
this.delegate = delegate;
|
||||
this.constraint = constraint;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListIterator<E> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(E element) {
|
||||
constraint.checkElement(element);
|
||||
delegate.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(E element) {
|
||||
constraint.checkElement(element);
|
||||
delegate.set(element);
|
||||
}
|
||||
}
|
||||
|
||||
static <E> Collection<E> constrainedTypePreservingCollection(Collection<E> collection, Constraint<E> constraint) {
|
||||
if (collection instanceof SortedSet) {
|
||||
return constrainedSortedSet((SortedSet<E>) collection, constraint);
|
||||
} else if (collection instanceof Set) {
|
||||
return constrainedSet((Set<E>) collection, constraint);
|
||||
} else if (collection instanceof List) {
|
||||
return constrainedList((List<E>) collection, constraint);
|
||||
} else {
|
||||
return constrainedCollection(collection, constraint);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(kevinb): For better performance, avoid making a copy of the elements by
|
||||
* having addAll() call add() repeatedly instead.
|
||||
*/
|
||||
|
||||
private static <E> Collection<E> checkElements(Collection<E> elements, Constraint<? super E> constraint) {
|
||||
Collection<E> copy = Lists.newArrayList(elements);
|
||||
for (E element : copy) {
|
||||
constraint.checkElement(element);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
}
|
199
sources/main/java/com/google/common/collect/ContiguousSet.java
Normal file
199
sources/main/java/com/google/common/collect/ContiguousSet.java
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* A sorted set of contiguous values in a given {@link DiscreteDomain}.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> Be extremely careful what you do with conceptually large
|
||||
* instances (such as
|
||||
* {@code ContiguousSet.create(Range.greaterThan(0), DiscreteDomain.integers()}).
|
||||
* Certain operations on such a set can be performed efficiently, but others
|
||||
* (such as {@link Set#hashCode} or {@link Collections#frequency}) can cause
|
||||
* major performance problems.
|
||||
*
|
||||
* @author Gregory Kick
|
||||
* @since 10.0
|
||||
*/
|
||||
@Beta
|
||||
@GwtCompatible(emulated = true)
|
||||
@SuppressWarnings("rawtypes") // allow ungenerified Comparable types
|
||||
public abstract class ContiguousSet<C extends Comparable> extends ImmutableSortedSet<C> {
|
||||
/**
|
||||
* Returns a {@code ContiguousSet} containing the same values in the given
|
||||
* domain {@linkplain Range#contains contained} by the range.
|
||||
*
|
||||
* @throws IllegalArgumentException if neither range nor the domain has a lower
|
||||
* bound, or if neither has an upper bound
|
||||
*
|
||||
* @since 13.0
|
||||
*/
|
||||
public static <C extends Comparable> ContiguousSet<C> create(Range<C> range, DiscreteDomain<C> domain) {
|
||||
checkNotNull(range);
|
||||
checkNotNull(domain);
|
||||
Range<C> effectiveRange = range;
|
||||
try {
|
||||
if (!range.hasLowerBound()) {
|
||||
effectiveRange = effectiveRange.intersection(Range.atLeast(domain.minValue()));
|
||||
}
|
||||
if (!range.hasUpperBound()) {
|
||||
effectiveRange = effectiveRange.intersection(Range.atMost(domain.maxValue()));
|
||||
}
|
||||
} catch (NoSuchElementException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
// Per class spec, we are allowed to throw CCE if necessary
|
||||
boolean empty = effectiveRange.isEmpty() || Range.compareOrThrow(range.lowerBound.leastValueAbove(domain),
|
||||
range.upperBound.greatestValueBelow(domain)) > 0;
|
||||
|
||||
return empty ? new EmptyContiguousSet<C>(domain) : new RegularContiguousSet<C>(effectiveRange, domain);
|
||||
}
|
||||
|
||||
final DiscreteDomain<C> domain;
|
||||
|
||||
ContiguousSet(DiscreteDomain<C> domain) {
|
||||
super(Ordering.natural());
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContiguousSet<C> headSet(C toElement) {
|
||||
return headSetImpl(checkNotNull(toElement), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 12.0
|
||||
*/
|
||||
@GwtIncompatible("NavigableSet")
|
||||
@Override
|
||||
public ContiguousSet<C> headSet(C toElement, boolean inclusive) {
|
||||
return headSetImpl(checkNotNull(toElement), inclusive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContiguousSet<C> subSet(C fromElement, C toElement) {
|
||||
checkNotNull(fromElement);
|
||||
checkNotNull(toElement);
|
||||
checkArgument(comparator().compare(fromElement, toElement) <= 0);
|
||||
return subSetImpl(fromElement, true, toElement, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 12.0
|
||||
*/
|
||||
@GwtIncompatible("NavigableSet")
|
||||
@Override
|
||||
public ContiguousSet<C> subSet(C fromElement, boolean fromInclusive, C toElement, boolean toInclusive) {
|
||||
checkNotNull(fromElement);
|
||||
checkNotNull(toElement);
|
||||
checkArgument(comparator().compare(fromElement, toElement) <= 0);
|
||||
return subSetImpl(fromElement, fromInclusive, toElement, toInclusive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContiguousSet<C> tailSet(C fromElement) {
|
||||
return tailSetImpl(checkNotNull(fromElement), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 12.0
|
||||
*/
|
||||
@GwtIncompatible("NavigableSet")
|
||||
@Override
|
||||
public ContiguousSet<C> tailSet(C fromElement, boolean inclusive) {
|
||||
return tailSetImpl(checkNotNull(fromElement), inclusive);
|
||||
}
|
||||
|
||||
/*
|
||||
* These methods perform most headSet, subSet, and tailSet logic, besides
|
||||
* parameter validation.
|
||||
*/
|
||||
/* @Override */ abstract ContiguousSet<C> headSetImpl(C toElement, boolean inclusive);
|
||||
|
||||
/* @Override */ abstract ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive, C toElement,
|
||||
boolean toInclusive);
|
||||
|
||||
/* @Override */ abstract ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive);
|
||||
|
||||
/**
|
||||
* Returns the set of values that are contained in both this set and the other.
|
||||
*
|
||||
* <p>
|
||||
* This method should always be used instead of {@link Sets#intersection} for
|
||||
* {@link ContiguousSet} instances.
|
||||
*/
|
||||
public abstract ContiguousSet<C> intersection(ContiguousSet<C> other);
|
||||
|
||||
/**
|
||||
* Returns a range, closed on both ends, whose endpoints are the minimum and
|
||||
* maximum values contained in this set. This is equivalent to
|
||||
* {@code range(CLOSED, CLOSED)}.
|
||||
*
|
||||
* @throws NoSuchElementException if this set is empty
|
||||
*/
|
||||
public abstract Range<C> range();
|
||||
|
||||
/**
|
||||
* Returns the minimal range with the given boundary types for which all values
|
||||
* in this set are {@linkplain Range#contains(Comparable) contained} within the
|
||||
* range.
|
||||
*
|
||||
* <p>
|
||||
* Note that this method will return ranges with unbounded endpoints if
|
||||
* {@link BoundType#OPEN} is requested for a domain minimum or maximum. For
|
||||
* example, if {@code set} was created from the range
|
||||
* {@code [1..Integer.MAX_VALUE]} then {@code set.range(CLOSED, OPEN)} must
|
||||
* return {@code [1..∞)}.
|
||||
*
|
||||
* @throws NoSuchElementException if this set is empty
|
||||
*/
|
||||
public abstract Range<C> range(BoundType lowerBoundType, BoundType upperBoundType);
|
||||
|
||||
/**
|
||||
* Returns a short-hand representation of the contents such as
|
||||
* {@code "[1..100]"}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return range().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Not supported. {@code ContiguousSet} instances are constructed with
|
||||
* {@link #create}. This method exists only to hide {@link ImmutableSet#builder}
|
||||
* from consumers of {@code
|
||||
* ContiguousSet}.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Use {@link #create}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E> ImmutableSortedSet.Builder<E> builder() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
75
sources/main/java/com/google/common/collect/Count.java
Normal file
75
sources/main/java/com/google/common/collect/Count.java
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A mutable value of type {@code int}, for multisets to use in tracking counts
|
||||
* of values.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
final class Count implements Serializable {
|
||||
private int value;
|
||||
|
||||
Count(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int get() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public int getAndAdd(int delta) {
|
||||
int result = value;
|
||||
value = result + delta;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int addAndGet(int delta) {
|
||||
return value += delta;
|
||||
}
|
||||
|
||||
public void set(int newValue) {
|
||||
value = newValue;
|
||||
}
|
||||
|
||||
public int getAndSet(int newValue) {
|
||||
int result = value;
|
||||
value = newValue;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return obj instanceof Count && ((Count) obj).value == value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Integer.toString(value);
|
||||
}
|
||||
}
|
459
sources/main/java/com/google/common/collect/Cut.java
Normal file
459
sources/main/java/com/google/common/collect/Cut.java
Normal file
@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.primitives.Booleans;
|
||||
|
||||
/**
|
||||
* Implementation detail for the internal structure of {@link Range} instances.
|
||||
* Represents a unique way of "cutting" a "number line" (actually of instances
|
||||
* of type {@code C}, not necessarily "numbers") into two sections; this can be
|
||||
* done below a certain value, above a certain value, below all values or above
|
||||
* all values. With this object defined in this way, an interval can always be
|
||||
* represented by a pair of {@code Cut} instances.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
@GwtCompatible
|
||||
abstract class Cut<C extends Comparable> implements Comparable<Cut<C>>, Serializable {
|
||||
final C endpoint;
|
||||
|
||||
Cut(@Nullable C endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
abstract boolean isLessThan(C value);
|
||||
|
||||
abstract BoundType typeAsLowerBound();
|
||||
|
||||
abstract BoundType typeAsUpperBound();
|
||||
|
||||
abstract Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain);
|
||||
|
||||
abstract Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain);
|
||||
|
||||
abstract void describeAsLowerBound(StringBuilder sb);
|
||||
|
||||
abstract void describeAsUpperBound(StringBuilder sb);
|
||||
|
||||
abstract C leastValueAbove(DiscreteDomain<C> domain);
|
||||
|
||||
abstract C greatestValueBelow(DiscreteDomain<C> domain);
|
||||
|
||||
/*
|
||||
* The canonical form is a BelowValue cut whenever possible, otherwise
|
||||
* ABOVE_ALL, or (only in the case of types that are unbounded below) BELOW_ALL.
|
||||
*/
|
||||
Cut<C> canonical(DiscreteDomain<C> domain) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// note: overriden by {BELOW,ABOVE}_ALL
|
||||
@Override
|
||||
public int compareTo(Cut<C> that) {
|
||||
if (that == belowAll()) {
|
||||
return 1;
|
||||
}
|
||||
if (that == aboveAll()) {
|
||||
return -1;
|
||||
}
|
||||
int result = Range.compareOrThrow(endpoint, that.endpoint);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
// same value. below comes before above
|
||||
return Booleans.compare(this instanceof AboveValue, that instanceof AboveValue);
|
||||
}
|
||||
|
||||
C endpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // catching CCE
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Cut) {
|
||||
// It might not really be a Cut<C>, but we'll catch a CCE if it's not
|
||||
Cut<C> that = (Cut<C>) obj;
|
||||
try {
|
||||
int compareResult = compareTo(that);
|
||||
return compareResult == 0;
|
||||
} catch (ClassCastException ignored) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The implementation neither produces nor consumes any non-null instance of
|
||||
* type C, so casting the type parameter is safe.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <C extends Comparable> Cut<C> belowAll() {
|
||||
return (Cut<C>) BelowAll.INSTANCE;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
|
||||
private static final class BelowAll extends Cut<Comparable<?>> {
|
||||
private static final BelowAll INSTANCE = new BelowAll();
|
||||
|
||||
private BelowAll() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
Comparable<?> endpoint() {
|
||||
throw new IllegalStateException("range unbounded on this side");
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isLessThan(Comparable<?> value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
BoundType typeAsLowerBound() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
BoundType typeAsUpperBound() {
|
||||
throw new AssertionError("this statement should be unreachable");
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<Comparable<?>> withLowerBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<Comparable<?>> withUpperBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain) {
|
||||
throw new AssertionError("this statement should be unreachable");
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeAsLowerBound(StringBuilder sb) {
|
||||
sb.append("(-\u221e");
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeAsUpperBound(StringBuilder sb) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Override
|
||||
Comparable<?> leastValueAbove(DiscreteDomain<Comparable<?>> domain) {
|
||||
return domain.minValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
Comparable<?> greatestValueBelow(DiscreteDomain<Comparable<?>> domain) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<Comparable<?>> canonical(DiscreteDomain<Comparable<?>> domain) {
|
||||
try {
|
||||
return Cut.<Comparable<?>>belowValue(domain.minValue());
|
||||
} catch (NoSuchElementException e) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Cut<Comparable<?>> o) {
|
||||
return (o == this) ? 0 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "-\u221e";
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The implementation neither produces nor consumes any non-null instance of
|
||||
* type C, so casting the type parameter is safe.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <C extends Comparable> Cut<C> aboveAll() {
|
||||
return (Cut<C>) AboveAll.INSTANCE;
|
||||
}
|
||||
|
||||
private static final class AboveAll extends Cut<Comparable<?>> {
|
||||
private static final AboveAll INSTANCE = new AboveAll();
|
||||
|
||||
private AboveAll() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
Comparable<?> endpoint() {
|
||||
throw new IllegalStateException("range unbounded on this side");
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isLessThan(Comparable<?> value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
BoundType typeAsLowerBound() {
|
||||
throw new AssertionError("this statement should be unreachable");
|
||||
}
|
||||
|
||||
@Override
|
||||
BoundType typeAsUpperBound() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<Comparable<?>> withLowerBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain) {
|
||||
throw new AssertionError("this statement should be unreachable");
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<Comparable<?>> withUpperBoundType(BoundType boundType, DiscreteDomain<Comparable<?>> domain) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeAsLowerBound(StringBuilder sb) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeAsUpperBound(StringBuilder sb) {
|
||||
sb.append("+\u221e)");
|
||||
}
|
||||
|
||||
@Override
|
||||
Comparable<?> leastValueAbove(DiscreteDomain<Comparable<?>> domain) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Override
|
||||
Comparable<?> greatestValueBelow(DiscreteDomain<Comparable<?>> domain) {
|
||||
return domain.maxValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Cut<Comparable<?>> o) {
|
||||
return (o == this) ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "+\u221e";
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
static <C extends Comparable> Cut<C> belowValue(C endpoint) {
|
||||
return new BelowValue<C>(endpoint);
|
||||
}
|
||||
|
||||
private static final class BelowValue<C extends Comparable> extends Cut<C> {
|
||||
BelowValue(C endpoint) {
|
||||
super(checkNotNull(endpoint));
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isLessThan(C value) {
|
||||
return Range.compareOrThrow(endpoint, value) <= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
BoundType typeAsLowerBound() {
|
||||
return BoundType.CLOSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
BoundType typeAsUpperBound() {
|
||||
return BoundType.OPEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) {
|
||||
switch (boundType) {
|
||||
case CLOSED:
|
||||
return this;
|
||||
case OPEN:
|
||||
@Nullable
|
||||
C previous = domain.previous(endpoint);
|
||||
return (previous == null) ? Cut.<C>belowAll() : new AboveValue<C>(previous);
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) {
|
||||
switch (boundType) {
|
||||
case CLOSED:
|
||||
@Nullable
|
||||
C previous = domain.previous(endpoint);
|
||||
return (previous == null) ? Cut.<C>aboveAll() : new AboveValue<C>(previous);
|
||||
case OPEN:
|
||||
return this;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeAsLowerBound(StringBuilder sb) {
|
||||
sb.append('[').append(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeAsUpperBound(StringBuilder sb) {
|
||||
sb.append(endpoint).append(')');
|
||||
}
|
||||
|
||||
@Override
|
||||
C leastValueAbove(DiscreteDomain<C> domain) {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
C greatestValueBelow(DiscreteDomain<C> domain) {
|
||||
return domain.previous(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return endpoint.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "\\" + endpoint + "/";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
static <C extends Comparable> Cut<C> aboveValue(C endpoint) {
|
||||
return new AboveValue<C>(endpoint);
|
||||
}
|
||||
|
||||
private static final class AboveValue<C extends Comparable> extends Cut<C> {
|
||||
AboveValue(C endpoint) {
|
||||
super(checkNotNull(endpoint));
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isLessThan(C value) {
|
||||
return Range.compareOrThrow(endpoint, value) < 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
BoundType typeAsLowerBound() {
|
||||
return BoundType.OPEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
BoundType typeAsUpperBound() {
|
||||
return BoundType.CLOSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) {
|
||||
switch (boundType) {
|
||||
case OPEN:
|
||||
return this;
|
||||
case CLOSED:
|
||||
@Nullable
|
||||
C next = domain.next(endpoint);
|
||||
return (next == null) ? Cut.<C>belowAll() : belowValue(next);
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) {
|
||||
switch (boundType) {
|
||||
case OPEN:
|
||||
@Nullable
|
||||
C next = domain.next(endpoint);
|
||||
return (next == null) ? Cut.<C>aboveAll() : belowValue(next);
|
||||
case CLOSED:
|
||||
return this;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeAsLowerBound(StringBuilder sb) {
|
||||
sb.append('(').append(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
void describeAsUpperBound(StringBuilder sb) {
|
||||
sb.append(endpoint).append(']');
|
||||
}
|
||||
|
||||
@Override
|
||||
C leastValueAbove(DiscreteDomain<C> domain) {
|
||||
return domain.next(endpoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
C greatestValueBelow(DiscreteDomain<C> domain) {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
Cut<C> canonical(DiscreteDomain<C> domain) {
|
||||
C next = leastValueAbove(domain);
|
||||
return (next != null) ? belowValue(next) : Cut.<C>aboveAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ~endpoint.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "/" + endpoint + "\\";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A {@code RegularImmutableTable} optimized for dense data.
|
||||
*/
|
||||
@GwtCompatible
|
||||
@Immutable
|
||||
final class DenseImmutableTable<R, C, V> extends RegularImmutableTable<R, C, V> {
|
||||
private final ImmutableMap<R, Integer> rowKeyToIndex;
|
||||
private final ImmutableMap<C, Integer> columnKeyToIndex;
|
||||
private final ImmutableMap<R, Map<C, V>> rowMap;
|
||||
private final ImmutableMap<C, Map<R, V>> columnMap;
|
||||
private final int[] rowCounts;
|
||||
private final int[] columnCounts;
|
||||
private final V[][] values;
|
||||
private final int[] iterationOrderRow;
|
||||
private final int[] iterationOrderColumn;
|
||||
|
||||
private static <E> ImmutableMap<E, Integer> makeIndex(ImmutableSet<E> set) {
|
||||
ImmutableMap.Builder<E, Integer> indexBuilder = ImmutableMap.builder();
|
||||
int i = 0;
|
||||
for (E key : set) {
|
||||
indexBuilder.put(key, i);
|
||||
i++;
|
||||
}
|
||||
return indexBuilder.build();
|
||||
}
|
||||
|
||||
DenseImmutableTable(ImmutableList<Cell<R, C, V>> cellList, ImmutableSet<R> rowSpace, ImmutableSet<C> columnSpace) {
|
||||
@SuppressWarnings("unchecked")
|
||||
V[][] array = (V[][]) new Object[rowSpace.size()][columnSpace.size()];
|
||||
this.values = array;
|
||||
this.rowKeyToIndex = makeIndex(rowSpace);
|
||||
this.columnKeyToIndex = makeIndex(columnSpace);
|
||||
rowCounts = new int[rowKeyToIndex.size()];
|
||||
columnCounts = new int[columnKeyToIndex.size()];
|
||||
int[] iterationOrderRow = new int[cellList.size()];
|
||||
int[] iterationOrderColumn = new int[cellList.size()];
|
||||
for (int i = 0; i < cellList.size(); i++) {
|
||||
Cell<R, C, V> cell = cellList.get(i);
|
||||
R rowKey = cell.getRowKey();
|
||||
C columnKey = cell.getColumnKey();
|
||||
int rowIndex = rowKeyToIndex.get(rowKey);
|
||||
int columnIndex = columnKeyToIndex.get(columnKey);
|
||||
V existingValue = values[rowIndex][columnIndex];
|
||||
checkArgument(existingValue == null, "duplicate key: (%s, %s)", rowKey, columnKey);
|
||||
values[rowIndex][columnIndex] = cell.getValue();
|
||||
rowCounts[rowIndex]++;
|
||||
columnCounts[columnIndex]++;
|
||||
iterationOrderRow[i] = rowIndex;
|
||||
iterationOrderColumn[i] = columnIndex;
|
||||
}
|
||||
this.iterationOrderRow = iterationOrderRow;
|
||||
this.iterationOrderColumn = iterationOrderColumn;
|
||||
this.rowMap = new RowMap();
|
||||
this.columnMap = new ColumnMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* An immutable map implementation backed by an indexed nullable array.
|
||||
*/
|
||||
private abstract static class ImmutableArrayMap<K, V> extends ImmutableMap<K, V> {
|
||||
private final int size;
|
||||
|
||||
ImmutableArrayMap(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
abstract ImmutableMap<K, Integer> keyToIndex();
|
||||
|
||||
// True if getValue never returns null.
|
||||
private boolean isFull() {
|
||||
return size == keyToIndex().size();
|
||||
}
|
||||
|
||||
K getKey(int index) {
|
||||
return keyToIndex().keySet().asList().get(index);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
abstract V getValue(int keyIndex);
|
||||
|
||||
@Override
|
||||
ImmutableSet<K> createKeySet() {
|
||||
return isFull() ? keyToIndex().keySet() : super.createKeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(@Nullable Object key) {
|
||||
Integer keyIndex = keyToIndex().get(key);
|
||||
return (keyIndex == null) ? null : getValue(keyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSet<Entry<K, V>> createEntrySet() {
|
||||
return new ImmutableMapEntrySet<K, V>() {
|
||||
@Override
|
||||
ImmutableMap<K, V> map() {
|
||||
return ImmutableArrayMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<Entry<K, V>> iterator() {
|
||||
return new AbstractIterator<Entry<K, V>>() {
|
||||
private int index = -1;
|
||||
private final int maxIndex = keyToIndex().size();
|
||||
|
||||
@Override
|
||||
protected Entry<K, V> computeNext() {
|
||||
for (index++; index < maxIndex; index++) {
|
||||
V value = getValue(index);
|
||||
if (value != null) {
|
||||
return Maps.immutableEntry(getKey(index), value);
|
||||
}
|
||||
}
|
||||
return endOfData();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private final class Row extends ImmutableArrayMap<C, V> {
|
||||
private final int rowIndex;
|
||||
|
||||
Row(int rowIndex) {
|
||||
super(rowCounts[rowIndex]);
|
||||
this.rowIndex = rowIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMap<C, Integer> keyToIndex() {
|
||||
return columnKeyToIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
V getValue(int keyIndex) {
|
||||
return values[rowIndex][keyIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final class Column extends ImmutableArrayMap<R, V> {
|
||||
private final int columnIndex;
|
||||
|
||||
Column(int columnIndex) {
|
||||
super(columnCounts[columnIndex]);
|
||||
this.columnIndex = columnIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMap<R, Integer> keyToIndex() {
|
||||
return rowKeyToIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
V getValue(int keyIndex) {
|
||||
return values[keyIndex][columnIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final class RowMap extends ImmutableArrayMap<R, Map<C, V>> {
|
||||
private RowMap() {
|
||||
super(rowCounts.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMap<R, Integer> keyToIndex() {
|
||||
return rowKeyToIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<C, V> getValue(int keyIndex) {
|
||||
return new Row(keyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private final class ColumnMap extends ImmutableArrayMap<C, Map<R, V>> {
|
||||
private ColumnMap() {
|
||||
super(columnCounts.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMap<C, Integer> keyToIndex() {
|
||||
return columnKeyToIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<R, V> getValue(int keyIndex) {
|
||||
return new Column(keyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<C, Map<R, V>> columnMap() {
|
||||
return columnMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<R, Map<C, V>> rowMap() {
|
||||
return rowMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
Integer rowIndex = rowKeyToIndex.get(rowKey);
|
||||
Integer columnIndex = columnKeyToIndex.get(columnKey);
|
||||
return ((rowIndex == null) || (columnIndex == null)) ? null : values[rowIndex][columnIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return iterationOrderRow.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
Cell<R, C, V> getCell(int index) {
|
||||
int rowIndex = iterationOrderRow[index];
|
||||
int columnIndex = iterationOrderColumn[index];
|
||||
R rowKey = rowKeySet().asList().get(rowIndex);
|
||||
C columnKey = columnKeySet().asList().get(columnIndex);
|
||||
V value = values[rowIndex][columnIndex];
|
||||
return cellOf(rowKey, columnKey, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
V getValue(int index) {
|
||||
return values[iterationOrderRow[index]][iterationOrderColumn[index]];
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A descending wrapper around an {@code ImmutableSortedMultiset}
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@SuppressWarnings("serial") // uses writeReplace, not default serialization
|
||||
final class DescendingImmutableSortedMultiset<E> extends ImmutableSortedMultiset<E> {
|
||||
private final transient ImmutableSortedMultiset<E> forward;
|
||||
|
||||
DescendingImmutableSortedMultiset(ImmutableSortedMultiset<E> forward) {
|
||||
this.forward = forward;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int count(@Nullable Object element) {
|
||||
return forward.count(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> firstEntry() {
|
||||
return forward.lastEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> lastEntry() {
|
||||
return forward.firstEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return forward.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedSet<E> elementSet() {
|
||||
return forward.elementSet().descendingSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
Entry<E> getEntry(int index) {
|
||||
return forward.entrySet().asList().reverse().get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedMultiset<E> descendingMultiset() {
|
||||
return forward;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
|
||||
return forward.tailMultiset(upperBound, boundType).descendingMultiset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
|
||||
return forward.headMultiset(lowerBound, boundType).descendingMultiset();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return forward.isPartialView();
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* Skeletal implementation of {@link ImmutableSortedSet#descendingSet()}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
class DescendingImmutableSortedSet<E> extends ImmutableSortedSet<E> {
|
||||
private final ImmutableSortedSet<E> forward;
|
||||
|
||||
DescendingImmutableSortedSet(ImmutableSortedSet<E> forward) {
|
||||
super(Ordering.from(forward.comparator()).reverse());
|
||||
this.forward = forward;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return forward.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<E> iterator() {
|
||||
return forward.descendingIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSortedSet<E> headSetImpl(E toElement, boolean inclusive) {
|
||||
return forward.tailSet(toElement, inclusive).descendingSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSortedSet<E> subSetImpl(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
|
||||
return forward.subSet(toElement, toInclusive, fromElement, fromInclusive).descendingSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSortedSet<E> tailSetImpl(E fromElement, boolean inclusive) {
|
||||
return forward.headSet(fromElement, inclusive).descendingSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@GwtIncompatible("NavigableSet")
|
||||
public ImmutableSortedSet<E> descendingSet() {
|
||||
return forward;
|
||||
}
|
||||
|
||||
@Override
|
||||
@GwtIncompatible("NavigableSet")
|
||||
public UnmodifiableIterator<E> descendingIterator() {
|
||||
return forward.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
@GwtIncompatible("NavigableSet")
|
||||
ImmutableSortedSet<E> createDescendingSet() {
|
||||
throw new AssertionError("should never be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public E lower(E element) {
|
||||
return forward.higher(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E floor(E element) {
|
||||
return forward.ceiling(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E ceiling(E element) {
|
||||
return forward.floor(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E higher(E element) {
|
||||
return forward.lower(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
int indexOf(@Nullable Object target) {
|
||||
int index = forward.indexOf(target);
|
||||
if (index == -1) {
|
||||
return index;
|
||||
} else {
|
||||
return size() - 1 - index;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return forward.isPartialView();
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A skeleton implementation of a descending multiset. Only needs
|
||||
* {@code forwardMultiset()} and {@code entryIterator()}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
abstract class DescendingMultiset<E> extends ForwardingMultiset<E> implements SortedMultiset<E> {
|
||||
abstract SortedMultiset<E> forwardMultiset();
|
||||
|
||||
private transient Comparator<? super E> comparator;
|
||||
|
||||
@Override
|
||||
public Comparator<? super E> comparator() {
|
||||
Comparator<? super E> result = comparator;
|
||||
if (result == null) {
|
||||
return comparator = Ordering.from(forwardMultiset().comparator()).<E>reverse();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private transient NavigableSet<E> elementSet;
|
||||
|
||||
@Override
|
||||
public NavigableSet<E> elementSet() {
|
||||
NavigableSet<E> result = elementSet;
|
||||
if (result == null) {
|
||||
return elementSet = new SortedMultisets.NavigableElementSet<E>(this);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> pollFirstEntry() {
|
||||
return forwardMultiset().pollLastEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> pollLastEntry() {
|
||||
return forwardMultiset().pollFirstEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> headMultiset(E toElement, BoundType boundType) {
|
||||
return forwardMultiset().tailMultiset(toElement, boundType).descendingMultiset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> subMultiset(E fromElement, BoundType fromBoundType, E toElement, BoundType toBoundType) {
|
||||
return forwardMultiset().subMultiset(toElement, toBoundType, fromElement, fromBoundType).descendingMultiset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> tailMultiset(E fromElement, BoundType boundType) {
|
||||
return forwardMultiset().headMultiset(fromElement, boundType).descendingMultiset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Multiset<E> delegate() {
|
||||
return forwardMultiset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> descendingMultiset() {
|
||||
return forwardMultiset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> firstEntry() {
|
||||
return forwardMultiset().lastEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> lastEntry() {
|
||||
return forwardMultiset().firstEntry();
|
||||
}
|
||||
|
||||
abstract Iterator<Entry<E>> entryIterator();
|
||||
|
||||
private transient Set<Entry<E>> entrySet;
|
||||
|
||||
@Override
|
||||
public Set<Entry<E>> entrySet() {
|
||||
Set<Entry<E>> result = entrySet;
|
||||
return (result == null) ? entrySet = createEntrySet() : result;
|
||||
}
|
||||
|
||||
Set<Entry<E>> createEntrySet() {
|
||||
return new Multisets.EntrySet<E>() {
|
||||
@Override
|
||||
Multiset<E> multiset() {
|
||||
return DescendingMultiset.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<E>> iterator() {
|
||||
return entryIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return forwardMultiset().entrySet().size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Multisets.iteratorImpl(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return standardToArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return standardToArray(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return entrySet().toString();
|
||||
}
|
||||
}
|
275
sources/main/java/com/google/common/collect/DiscreteDomain.java
Normal file
275
sources/main/java/com/google/common/collect/DiscreteDomain.java
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A descriptor for a <i>discrete</i> {@code Comparable} domain such as all
|
||||
* {@link Integer} instances. A discrete domain is one that supports the three
|
||||
* basic operations: {@link #next}, {@link #previous} and {@link #distance},
|
||||
* according to their specifications. The methods {@link #minValue} and
|
||||
* {@link #maxValue} should also be overridden for bounded types.
|
||||
*
|
||||
* <p>
|
||||
* A discrete domain always represents the <i>entire</i> set of values of its
|
||||
* type; it cannot represent partial domains such as "prime integers" or
|
||||
* "strings of length 5."
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide section on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/RangesExplained#Discrete_Domains">
|
||||
* {@code DiscreteDomain}</a>.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 10.0
|
||||
*/
|
||||
@GwtCompatible
|
||||
@Beta
|
||||
public abstract class DiscreteDomain<C extends Comparable> {
|
||||
|
||||
/**
|
||||
* Returns the discrete domain for values of type {@code Integer}.
|
||||
*
|
||||
* @since 14.0 (since 10.0 as {@code DiscreteDomains.integers()})
|
||||
*/
|
||||
public static DiscreteDomain<Integer> integers() {
|
||||
return IntegerDomain.INSTANCE;
|
||||
}
|
||||
|
||||
private static final class IntegerDomain extends DiscreteDomain<Integer> implements Serializable {
|
||||
private static final IntegerDomain INSTANCE = new IntegerDomain();
|
||||
|
||||
@Override
|
||||
public Integer next(Integer value) {
|
||||
int i = value;
|
||||
return (i == Integer.MAX_VALUE) ? null : i + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer previous(Integer value) {
|
||||
int i = value;
|
||||
return (i == Integer.MIN_VALUE) ? null : i - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long distance(Integer start, Integer end) {
|
||||
return (long) end - start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer minValue() {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer maxValue() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DiscreteDomain.integers()";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discrete domain for values of type {@code Long}.
|
||||
*
|
||||
* @since 14.0 (since 10.0 as {@code DiscreteDomains.longs()})
|
||||
*/
|
||||
public static DiscreteDomain<Long> longs() {
|
||||
return LongDomain.INSTANCE;
|
||||
}
|
||||
|
||||
private static final class LongDomain extends DiscreteDomain<Long> implements Serializable {
|
||||
private static final LongDomain INSTANCE = new LongDomain();
|
||||
|
||||
@Override
|
||||
public Long next(Long value) {
|
||||
long l = value;
|
||||
return (l == Long.MAX_VALUE) ? null : l + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long previous(Long value) {
|
||||
long l = value;
|
||||
return (l == Long.MIN_VALUE) ? null : l - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long distance(Long start, Long end) {
|
||||
long result = end - start;
|
||||
if (end > start && result < 0) { // overflow
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
if (end < start && result > 0) { // underflow
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long minValue() {
|
||||
return Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long maxValue() {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DiscreteDomain.longs()";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the discrete domain for values of type {@code BigInteger}.
|
||||
*
|
||||
* @since 15.0
|
||||
*/
|
||||
public static DiscreteDomain<BigInteger> bigIntegers() {
|
||||
return BigIntegerDomain.INSTANCE;
|
||||
}
|
||||
|
||||
private static final class BigIntegerDomain extends DiscreteDomain<BigInteger> implements Serializable {
|
||||
private static final BigIntegerDomain INSTANCE = new BigIntegerDomain();
|
||||
|
||||
private static final BigInteger MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE);
|
||||
private static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
|
||||
|
||||
@Override
|
||||
public BigInteger next(BigInteger value) {
|
||||
return value.add(BigInteger.ONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger previous(BigInteger value) {
|
||||
return value.subtract(BigInteger.ONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long distance(BigInteger start, BigInteger end) {
|
||||
return end.subtract(start).max(MIN_LONG).min(MAX_LONG).longValue();
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DiscreteDomain.bigIntegers()";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected DiscreteDomain() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique least value of type {@code C} that is greater than
|
||||
* {@code value}, or {@code null} if none exists. Inverse operation to
|
||||
* {@link #previous}.
|
||||
*
|
||||
* @param value any value of type {@code C}
|
||||
* @return the least value greater than {@code value}, or {@code null} if
|
||||
* {@code value} is {@code maxValue()}
|
||||
*/
|
||||
public abstract C next(C value);
|
||||
|
||||
/**
|
||||
* Returns the unique greatest value of type {@code C} that is less than
|
||||
* {@code value}, or {@code null} if none exists. Inverse operation to
|
||||
* {@link #next}.
|
||||
*
|
||||
* @param value any value of type {@code C}
|
||||
* @return the greatest value less than {@code value}, or {@code null} if
|
||||
* {@code value} is {@code minValue()}
|
||||
*/
|
||||
public abstract C previous(C value);
|
||||
|
||||
/**
|
||||
* Returns a signed value indicating how many nested invocations of
|
||||
* {@link #next} (if positive) or {@link #previous} (if negative) are needed to
|
||||
* reach {@code end} starting from {@code start}. For example, if {@code end =
|
||||
* next(next(next(start)))}, then {@code distance(start, end) == 3} and {@code
|
||||
* distance(end, start) == -3}. As well, {@code distance(a, a)} is always zero.
|
||||
*
|
||||
* <p>
|
||||
* Note that this function is necessarily well-defined for any discrete type.
|
||||
*
|
||||
* @return the distance as described above, or {@link Long#MIN_VALUE} or
|
||||
* {@link Long#MAX_VALUE} if the distance is too small or too large,
|
||||
* respectively.
|
||||
*/
|
||||
public abstract long distance(C start, C end);
|
||||
|
||||
/**
|
||||
* Returns the minimum value of type {@code C}, if it has one. The minimum value
|
||||
* is the unique value for which {@link Comparable#compareTo(Object)} never
|
||||
* returns a positive value for any input of type {@code C}.
|
||||
*
|
||||
* <p>
|
||||
* The default implementation throws {@code NoSuchElementException}.
|
||||
*
|
||||
* @return the minimum value of type {@code C}; never null
|
||||
* @throws NoSuchElementException if the type has no (practical) minimum value;
|
||||
* for example, {@link java.math.BigInteger}
|
||||
*/
|
||||
public C minValue() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum value of type {@code C}, if it has one. The maximum value
|
||||
* is the unique value for which {@link Comparable#compareTo(Object)} never
|
||||
* returns a negative value for any input of type {@code C}.
|
||||
*
|
||||
* <p>
|
||||
* The default implementation throws {@code NoSuchElementException}.
|
||||
*
|
||||
* @return the maximum value of type {@code C}; never null
|
||||
* @throws NoSuchElementException if the type has no (practical) maximum value;
|
||||
* for example, {@link java.math.BigInteger}
|
||||
*/
|
||||
public C maxValue() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* An empty contiguous set.
|
||||
*
|
||||
* @author Gregory Kick
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
@SuppressWarnings("unchecked") // allow ungenerified Comparable types
|
||||
final class EmptyContiguousSet<C extends Comparable> extends ContiguousSet<C> {
|
||||
EmptyContiguousSet(DiscreteDomain<C> domain) {
|
||||
super(domain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public C first() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public C last() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContiguousSet<C> intersection(ContiguousSet<C> other) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range<C> range() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range<C> range(BoundType lowerBoundType, BoundType upperBoundType) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
ContiguousSet<C> headSetImpl(C toElement, boolean inclusive) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive, C toElement, boolean toInclusive) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
ContiguousSet<C> tailSetImpl(C fromElement, boolean fromInclusive) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@GwtIncompatible("not used by GWT emulation")
|
||||
@Override
|
||||
int indexOf(Object target) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<C> iterator() {
|
||||
return Iterators.emptyIterator();
|
||||
}
|
||||
|
||||
@GwtIncompatible("NavigableSet")
|
||||
@Override
|
||||
public UnmodifiableIterator<C> descendingIterator() {
|
||||
return Iterators.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<C> asList() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
if (object instanceof Set) {
|
||||
Set<?> that = (Set<?>) object;
|
||||
return that.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@GwtIncompatible("serialization")
|
||||
private static final class SerializedForm<C extends Comparable> implements Serializable {
|
||||
private final DiscreteDomain<C> domain;
|
||||
|
||||
private SerializedForm(DiscreteDomain<C> domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return new EmptyContiguousSet<C>(domain);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
@GwtIncompatible("serialization")
|
||||
@Override
|
||||
Object writeReplace() {
|
||||
return new SerializedForm<C>(domain);
|
||||
}
|
||||
|
||||
@GwtIncompatible("NavigableSet")
|
||||
ImmutableSortedSet<C> createDescendingSet() {
|
||||
return new EmptyImmutableSortedSet<C>(Ordering.natural().reverse());
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Bimap with no mappings.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
@SuppressWarnings("serial") // uses writeReplace(), not default serialization
|
||||
final class EmptyImmutableBiMap extends ImmutableBiMap<Object, Object> {
|
||||
static final EmptyImmutableBiMap INSTANCE = new EmptyImmutableBiMap();
|
||||
|
||||
private EmptyImmutableBiMap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBiMap<Object, Object> inverse() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(@Nullable Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSet<Entry<Object, Object>> entrySet() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSet<Entry<Object, Object>> createEntrySet() {
|
||||
throw new AssertionError("should never be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSetMultimap<Object, Object> asMultimap() {
|
||||
return ImmutableSetMultimap.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSet<Object> keySet() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object readResolve() {
|
||||
return INSTANCE; // preserve singleton property
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ImmutableListMultimap} with no entries.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
@GwtCompatible(serializable = true)
|
||||
class EmptyImmutableListMultimap extends ImmutableListMultimap<Object, Object> {
|
||||
static final EmptyImmutableListMultimap INSTANCE = new EmptyImmutableListMultimap();
|
||||
|
||||
private EmptyImmutableListMultimap() {
|
||||
super(ImmutableMap.<Object, ImmutableList<Object>>of(), 0);
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return INSTANCE; // preserve singleton property
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* An empty immutable set.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
@GwtCompatible(serializable = true, emulated = true)
|
||||
final class EmptyImmutableSet extends ImmutableSet<Object> {
|
||||
static final EmptyImmutableSet INSTANCE = new EmptyImmutableSet();
|
||||
|
||||
private EmptyImmutableSet() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> targets) {
|
||||
return targets.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<Object> iterator() {
|
||||
return Iterators.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
int copyIntoArray(Object[] dst, int offset) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<Object> asList() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
if (object instanceof Set) {
|
||||
Set<?> that = (Set<?>) object;
|
||||
return that.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isHashCodeFast() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
Object readResolve() {
|
||||
return INSTANCE; // preserve singleton property
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ImmutableListMultimap} with no entries.
|
||||
*
|
||||
* @author Mike Ward
|
||||
*/
|
||||
@GwtCompatible(serializable = true)
|
||||
class EmptyImmutableSetMultimap extends ImmutableSetMultimap<Object, Object> {
|
||||
static final EmptyImmutableSetMultimap INSTANCE = new EmptyImmutableSetMultimap();
|
||||
|
||||
private EmptyImmutableSetMultimap() {
|
||||
super(ImmutableMap.<Object, ImmutableSet<Object>>of(), 0, null);
|
||||
}
|
||||
|
||||
private Object readResolve() {
|
||||
return INSTANCE; // preserve singleton property
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* An empty immutable sorted map.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
@SuppressWarnings("serial") // uses writeReplace, not default serialization
|
||||
final class EmptyImmutableSortedMap<K, V> extends ImmutableSortedMap<K, V> {
|
||||
private final transient ImmutableSortedSet<K> keySet;
|
||||
|
||||
EmptyImmutableSortedMap(Comparator<? super K> comparator) {
|
||||
this.keySet = ImmutableSortedSet.emptySet(comparator);
|
||||
}
|
||||
|
||||
EmptyImmutableSortedMap(Comparator<? super K> comparator, ImmutableSortedMap<K, V> descendingMap) {
|
||||
super(descendingMap);
|
||||
this.keySet = ImmutableSortedSet.emptySet(comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(@Nullable Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedSet<K> keySet() {
|
||||
return keySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableCollection<V> values() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{}";
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSet<Entry<K, V>> entrySet() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSet<Entry<K, V>> createEntrySet() {
|
||||
throw new AssertionError("should never be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSetMultimap<K, V> asMultimap() {
|
||||
return ImmutableSetMultimap.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedMap<K, V> headMap(K toKey, boolean inclusive) {
|
||||
checkNotNull(toKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedMap<K, V> tailMap(K fromKey, boolean inclusive) {
|
||||
checkNotNull(fromKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSortedMap<K, V> createDescendingMap() {
|
||||
return new EmptyImmutableSortedMap<K, V>(Ordering.from(comparator()).reverse(), this);
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An empty immutable sorted multiset.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@SuppressWarnings("serial") // Uses writeReplace, not default serialization
|
||||
final class EmptyImmutableSortedMultiset<E> extends ImmutableSortedMultiset<E> {
|
||||
private final ImmutableSortedSet<E> elementSet;
|
||||
|
||||
EmptyImmutableSortedMultiset(Comparator<? super E> comparator) {
|
||||
this.elementSet = ImmutableSortedSet.emptySet(comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> firstEntry() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> lastEntry() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int count(@Nullable Object element) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> targets) {
|
||||
return targets.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedSet<E> elementSet() {
|
||||
return elementSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
Entry<E> getEntry(int index) {
|
||||
throw new AssertionError("should never be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
|
||||
checkNotNull(upperBound);
|
||||
checkNotNull(boundType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
|
||||
checkNotNull(lowerBound);
|
||||
checkNotNull(boundType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<E> iterator() {
|
||||
return Iterators.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
if (object instanceof Multiset) {
|
||||
Multiset<?> other = (Multiset<?>) object;
|
||||
return other.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
int copyIntoArray(Object[] dst, int offset) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<E> asList() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* An empty immutable sorted set.
|
||||
*
|
||||
* @author Jared Levy
|
||||
*/
|
||||
@GwtCompatible(serializable = true, emulated = true)
|
||||
@SuppressWarnings("serial") // uses writeReplace(), not default serialization
|
||||
class EmptyImmutableSortedSet<E> extends ImmutableSortedSet<E> {
|
||||
EmptyImmutableSortedSet(Comparator<? super E> comparator) {
|
||||
super(comparator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> targets) {
|
||||
return targets.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnmodifiableIterator<E> iterator() {
|
||||
return Iterators.emptyIterator();
|
||||
}
|
||||
|
||||
@GwtIncompatible("NavigableSet")
|
||||
@Override
|
||||
public UnmodifiableIterator<E> descendingIterator() {
|
||||
return Iterators.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<E> asList() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
int copyIntoArray(Object[] dst, int offset) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
if (object instanceof Set) {
|
||||
Set<?> that = (Set<?>) object;
|
||||
return that.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public E first() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E last() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSortedSet<E> headSetImpl(E toElement, boolean inclusive) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSortedSet<E> subSetImpl(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSortedSet<E> tailSetImpl(E fromElement, boolean inclusive) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
int indexOf(@Nullable Object target) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableSortedSet<E> createDescendingSet() {
|
||||
return new EmptyImmutableSortedSet<E>(Ordering.from(comparator).reverse());
|
||||
}
|
||||
}
|
146
sources/main/java/com/google/common/collect/EnumBiMap.java
Normal file
146
sources/main/java/com/google/common/collect/EnumBiMap.java
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* A {@code BiMap} backed by two {@code EnumMap} instances. Null keys and values
|
||||
* are not permitted. An {@code EnumBiMap} and its inverse are both
|
||||
* serializable.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
|
||||
* {@code BiMap}</a>.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
public final class EnumBiMap<K extends Enum<K>, V extends Enum<V>> extends AbstractBiMap<K, V> {
|
||||
private transient Class<K> keyType;
|
||||
private transient Class<V> valueType;
|
||||
|
||||
/**
|
||||
* Returns a new, empty {@code EnumBiMap} using the specified key and value
|
||||
* types.
|
||||
*
|
||||
* @param keyType the key type
|
||||
* @param valueType the value type
|
||||
*/
|
||||
public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V> create(Class<K> keyType, Class<V> valueType) {
|
||||
return new EnumBiMap<K, V>(keyType, valueType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new bimap with the same mappings as the specified map. If the
|
||||
* specified map is an {@code EnumBiMap}, the new bimap has the same types as
|
||||
* the provided map. Otherwise, the specified map must contain at least one
|
||||
* mapping, in order to determine the key and value types.
|
||||
*
|
||||
* @param map the map whose mappings are to be placed in this map
|
||||
* @throws IllegalArgumentException if map is not an {@code EnumBiMap} instance
|
||||
* and contains no mappings
|
||||
*/
|
||||
public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V> create(Map<K, V> map) {
|
||||
EnumBiMap<K, V> bimap = create(inferKeyType(map), inferValueType(map));
|
||||
bimap.putAll(map);
|
||||
return bimap;
|
||||
}
|
||||
|
||||
private EnumBiMap(Class<K> keyType, Class<V> valueType) {
|
||||
super(WellBehavedMap.wrap(new EnumMap<K, V>(keyType)), WellBehavedMap.wrap(new EnumMap<V, K>(valueType)));
|
||||
this.keyType = keyType;
|
||||
this.valueType = valueType;
|
||||
}
|
||||
|
||||
static <K extends Enum<K>> Class<K> inferKeyType(Map<K, ?> map) {
|
||||
if (map instanceof EnumBiMap) {
|
||||
return ((EnumBiMap<K, ?>) map).keyType();
|
||||
}
|
||||
if (map instanceof EnumHashBiMap) {
|
||||
return ((EnumHashBiMap<K, ?>) map).keyType();
|
||||
}
|
||||
checkArgument(!map.isEmpty());
|
||||
return map.keySet().iterator().next().getDeclaringClass();
|
||||
}
|
||||
|
||||
private static <V extends Enum<V>> Class<V> inferValueType(Map<?, V> map) {
|
||||
if (map instanceof EnumBiMap) {
|
||||
return ((EnumBiMap<?, V>) map).valueType;
|
||||
}
|
||||
checkArgument(!map.isEmpty());
|
||||
return map.values().iterator().next().getDeclaringClass();
|
||||
}
|
||||
|
||||
/** Returns the associated key type. */
|
||||
public Class<K> keyType() {
|
||||
return keyType;
|
||||
}
|
||||
|
||||
/** Returns the associated value type. */
|
||||
public Class<V> valueType() {
|
||||
return valueType;
|
||||
}
|
||||
|
||||
@Override
|
||||
K checkKey(K key) {
|
||||
return checkNotNull(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
V checkValue(V value) {
|
||||
return checkNotNull(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData the key class, value class, number of entries, first key, first
|
||||
* value, second key, second value, and so on.
|
||||
*/
|
||||
@GwtIncompatible("java.io.ObjectOutputStream")
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
stream.writeObject(keyType);
|
||||
stream.writeObject(valueType);
|
||||
Serialization.writeMap(this, stream);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // reading fields populated by writeObject
|
||||
@GwtIncompatible("java.io.ObjectInputStream")
|
||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
keyType = (Class<K>) stream.readObject();
|
||||
valueType = (Class<V>) stream.readObject();
|
||||
setDelegates(WellBehavedMap.wrap(new EnumMap<K, V>(keyType)),
|
||||
WellBehavedMap.wrap(new EnumMap<V, K>(valueType)));
|
||||
Serialization.populateMap(this, stream);
|
||||
}
|
||||
|
||||
@GwtIncompatible("not needed in emulated source.")
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
128
sources/main/java/com/google/common/collect/EnumHashBiMap.java
Normal file
128
sources/main/java/com/google/common/collect/EnumHashBiMap.java
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* A {@code BiMap} backed by an {@code EnumMap} instance for keys-to-values, and
|
||||
* a {@code HashMap} instance for values-to-keys. Null keys are not permitted,
|
||||
* but null values are. An {@code EnumHashBiMap} and its inverse are both
|
||||
* serializable.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
|
||||
* {@code BiMap}</a>.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
public final class EnumHashBiMap<K extends Enum<K>, V> extends AbstractBiMap<K, V> {
|
||||
private transient Class<K> keyType;
|
||||
|
||||
/**
|
||||
* Returns a new, empty {@code EnumHashBiMap} using the specified key type.
|
||||
*
|
||||
* @param keyType the key type
|
||||
*/
|
||||
public static <K extends Enum<K>, V> EnumHashBiMap<K, V> create(Class<K> keyType) {
|
||||
return new EnumHashBiMap<K, V>(keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new bimap with the same mappings as the specified map. If the
|
||||
* specified map is an {@code EnumHashBiMap} or an {@link EnumBiMap}, the new
|
||||
* bimap has the same key type as the input bimap. Otherwise, the specified map
|
||||
* must contain at least one mapping, in order to determine the key type.
|
||||
*
|
||||
* @param map the map whose mappings are to be placed in this map
|
||||
* @throws IllegalArgumentException if map is not an {@code EnumBiMap} or an
|
||||
* {@code EnumHashBiMap} instance and contains
|
||||
* no mappings
|
||||
*/
|
||||
public static <K extends Enum<K>, V> EnumHashBiMap<K, V> create(Map<K, ? extends V> map) {
|
||||
EnumHashBiMap<K, V> bimap = create(EnumBiMap.inferKeyType(map));
|
||||
bimap.putAll(map);
|
||||
return bimap;
|
||||
}
|
||||
|
||||
private EnumHashBiMap(Class<K> keyType) {
|
||||
super(WellBehavedMap.wrap(new EnumMap<K, V>(keyType)),
|
||||
Maps.<V, K>newHashMapWithExpectedSize(keyType.getEnumConstants().length));
|
||||
this.keyType = keyType;
|
||||
}
|
||||
|
||||
// Overriding these 3 methods to show that values may be null (but not keys)
|
||||
|
||||
@Override
|
||||
K checkKey(K key) {
|
||||
return checkNotNull(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, @Nullable V value) {
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V forcePut(K key, @Nullable V value) {
|
||||
return super.forcePut(key, value);
|
||||
}
|
||||
|
||||
/** Returns the associated key type. */
|
||||
public Class<K> keyType() {
|
||||
return keyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData the key class, number of entries, first key, first value, second
|
||||
* key, second value, and so on.
|
||||
*/
|
||||
@GwtIncompatible("java.io.ObjectOutputStream")
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
stream.writeObject(keyType);
|
||||
Serialization.writeMap(this, stream);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // reading field populated by writeObject
|
||||
@GwtIncompatible("java.io.ObjectInputStream")
|
||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
keyType = (Class<K>) stream.readObject();
|
||||
setDelegates(WellBehavedMap.wrap(new EnumMap<K, V>(keyType)),
|
||||
new HashMap<V, K>(keyType.getEnumConstants().length * 3 / 2));
|
||||
Serialization.populateMap(this, stream);
|
||||
}
|
||||
|
||||
@GwtIncompatible("only needed in emulated source.")
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
109
sources/main/java/com/google/common/collect/EnumMultiset.java
Normal file
109
sources/main/java/com/google/common/collect/EnumMultiset.java
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* Multiset implementation backed by an {@link EnumMap}.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
|
||||
* {@code Multiset}</a>.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
public final class EnumMultiset<E extends Enum<E>> extends AbstractMapBasedMultiset<E> {
|
||||
/** Creates an empty {@code EnumMultiset}. */
|
||||
public static <E extends Enum<E>> EnumMultiset<E> create(Class<E> type) {
|
||||
return new EnumMultiset<E>(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code EnumMultiset} containing the specified elements.
|
||||
*
|
||||
* <p>
|
||||
* This implementation is highly efficient when {@code elements} is itself a
|
||||
* {@link Multiset}.
|
||||
*
|
||||
* @param elements the elements that the multiset should contain
|
||||
* @throws IllegalArgumentException if {@code elements} is empty
|
||||
*/
|
||||
public static <E extends Enum<E>> EnumMultiset<E> create(Iterable<E> elements) {
|
||||
Iterator<E> iterator = elements.iterator();
|
||||
checkArgument(iterator.hasNext(), "EnumMultiset constructor passed empty Iterable");
|
||||
EnumMultiset<E> multiset = new EnumMultiset<E>(iterator.next().getDeclaringClass());
|
||||
Iterables.addAll(multiset, elements);
|
||||
return multiset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@code EnumMultiset} instance containing the given elements.
|
||||
* Unlike {@link EnumMultiset#create(Iterable)}, this method does not produce an
|
||||
* exception on an empty iterable.
|
||||
*
|
||||
* @since 14.0
|
||||
*/
|
||||
public static <E extends Enum<E>> EnumMultiset<E> create(Iterable<E> elements, Class<E> type) {
|
||||
EnumMultiset<E> result = create(type);
|
||||
Iterables.addAll(result, elements);
|
||||
return result;
|
||||
}
|
||||
|
||||
private transient Class<E> type;
|
||||
|
||||
/** Creates an empty {@code EnumMultiset}. */
|
||||
private EnumMultiset(Class<E> type) {
|
||||
super(WellBehavedMap.wrap(new EnumMap<E, Count>(type)));
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@GwtIncompatible("java.io.ObjectOutputStream")
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
stream.writeObject(type);
|
||||
Serialization.writeMultiset(this, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData the {@code Class<E>} for the enum type, the number of distinct
|
||||
* elements, the first element, its count, the second element, its
|
||||
* count, and so on
|
||||
*/
|
||||
@GwtIncompatible("java.io.ObjectInputStream")
|
||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
@SuppressWarnings("unchecked") // reading data stored by writeObject
|
||||
Class<E> localType = (Class<E>) stream.readObject();
|
||||
type = localType;
|
||||
setBackingMap(WellBehavedMap.wrap(new EnumMap<E, Count>(type)));
|
||||
Serialization.populateMultiset(this, stream);
|
||||
}
|
||||
|
||||
@GwtIncompatible("Not needed in emulated source")
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
138
sources/main/java/com/google/common/collect/EvictingQueue.java
Normal file
138
sources/main/java/com/google/common/collect/EvictingQueue.java
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Queue;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* A non-blocking queue which automatically evicts elements from the head of the
|
||||
* queue when attempting to add new elements onto the queue and it is full.
|
||||
*
|
||||
* <p>
|
||||
* An evicting queue must be configured with a maximum size. Each time an
|
||||
* element is added to a full queue, the queue automatically removes its head
|
||||
* element. This is different from conventional bounded queues, which either
|
||||
* block or reject new elements when full.
|
||||
*
|
||||
* <p>
|
||||
* This class is not thread-safe, and does not accept null elements.
|
||||
*
|
||||
* @author Kurt Alfred Kluever
|
||||
* @since 15.0
|
||||
*/
|
||||
@Beta
|
||||
@GwtIncompatible("java.util.ArrayDeque")
|
||||
public final class EvictingQueue<E> extends ForwardingQueue<E> implements Serializable {
|
||||
|
||||
private final Queue<E> delegate;
|
||||
|
||||
@VisibleForTesting
|
||||
final int maxSize;
|
||||
|
||||
private EvictingQueue(int maxSize) {
|
||||
checkArgument(maxSize >= 0, "maxSize (%s) must >= 0", maxSize);
|
||||
this.delegate = new ArrayDeque<E>(maxSize);
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new evicting queue that will hold up to {@code maxSize}
|
||||
* elements.
|
||||
*
|
||||
* <p>
|
||||
* When {@code maxSize} is zero, elements will be evicted immediately after
|
||||
* being added to the queue.
|
||||
*/
|
||||
public static <E> EvictingQueue<E> create(int maxSize) {
|
||||
return new EvictingQueue<E>(maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of additional elements that this queue can accept without
|
||||
* evicting; zero if the queue is currently full.
|
||||
*
|
||||
* @since 16.0
|
||||
*/
|
||||
public int remainingCapacity() {
|
||||
return maxSize - size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Queue<E> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given element to this queue. If the queue is currently full, the
|
||||
* element at the head of the queue is evicted to make room.
|
||||
*
|
||||
* @return {@code true} always
|
||||
*/
|
||||
@Override
|
||||
public boolean offer(E e) {
|
||||
return add(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given element to this queue. If the queue is currently full, the
|
||||
* element at the head of the queue is evicted to make room.
|
||||
*
|
||||
* @return {@code true} always
|
||||
*/
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
checkNotNull(e); // check before removing
|
||||
if (maxSize == 0) {
|
||||
return true;
|
||||
}
|
||||
if (size() == maxSize) {
|
||||
delegate.remove();
|
||||
}
|
||||
delegate.add(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> collection) {
|
||||
return standardAddAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
return delegate().contains(checkNotNull(object));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object object) {
|
||||
return delegate().remove(checkNotNull(object));
|
||||
}
|
||||
|
||||
// TODO(user): Do we want to checkNotNull each element in containsAll,
|
||||
// removeAll, and retainAll?
|
||||
|
||||
private static final long serialVersionUID = 0L;
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/** An ordering that compares objects according to a given order. */
|
||||
@GwtCompatible(serializable = true)
|
||||
final class ExplicitOrdering<T> extends Ordering<T> implements Serializable {
|
||||
final ImmutableMap<T, Integer> rankMap;
|
||||
|
||||
ExplicitOrdering(List<T> valuesInOrder) {
|
||||
this(buildRankMap(valuesInOrder));
|
||||
}
|
||||
|
||||
ExplicitOrdering(ImmutableMap<T, Integer> rankMap) {
|
||||
this.rankMap = rankMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(T left, T right) {
|
||||
return rank(left) - rank(right); // safe because both are nonnegative
|
||||
}
|
||||
|
||||
private int rank(T value) {
|
||||
Integer rank = rankMap.get(value);
|
||||
if (rank == null) {
|
||||
throw new IncomparableValueException(value);
|
||||
}
|
||||
return rank;
|
||||
}
|
||||
|
||||
private static <T> ImmutableMap<T, Integer> buildRankMap(List<T> valuesInOrder) {
|
||||
ImmutableMap.Builder<T, Integer> builder = ImmutableMap.builder();
|
||||
int rank = 0;
|
||||
for (T value : valuesInOrder) {
|
||||
builder.put(value, rank++);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
if (object instanceof ExplicitOrdering) {
|
||||
ExplicitOrdering<?> that = (ExplicitOrdering<?>) object;
|
||||
return this.rankMap.equals(that.rankMap);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return rankMap.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Ordering.explicit(" + rankMap.keySet() + ")";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Predicates.in;
|
||||
import static com.google.common.base.Predicates.not;
|
||||
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Maps.ImprovedAbstractMap;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Multimaps#filterEntries(Multimap, Predicate)}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
class FilteredEntryMultimap<K, V> extends AbstractMultimap<K, V> implements FilteredMultimap<K, V> {
|
||||
final Multimap<K, V> unfiltered;
|
||||
final Predicate<? super Entry<K, V>> predicate;
|
||||
|
||||
FilteredEntryMultimap(Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> predicate) {
|
||||
this.unfiltered = checkNotNull(unfiltered);
|
||||
this.predicate = checkNotNull(predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multimap<K, V> unfiltered() {
|
||||
return unfiltered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<? super Entry<K, V>> entryPredicate() {
|
||||
return predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return entries().size();
|
||||
}
|
||||
|
||||
private boolean satisfies(K key, V value) {
|
||||
return predicate.apply(Maps.immutableEntry(key, value));
|
||||
}
|
||||
|
||||
final class ValuePredicate implements Predicate<V> {
|
||||
private final K key;
|
||||
|
||||
ValuePredicate(K key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(@Nullable V value) {
|
||||
return satisfies(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
static <E> Collection<E> filterCollection(Collection<E> collection, Predicate<? super E> predicate) {
|
||||
if (collection instanceof Set) {
|
||||
return Sets.filter((Set<E>) collection, predicate);
|
||||
} else {
|
||||
return Collections2.filter(collection, predicate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(@Nullable Object key) {
|
||||
return asMap().get(key) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> removeAll(@Nullable Object key) {
|
||||
return Objects.firstNonNull(asMap().remove(key), unmodifiableEmptyCollection());
|
||||
}
|
||||
|
||||
Collection<V> unmodifiableEmptyCollection() {
|
||||
// These return false, rather than throwing a UOE, on remove calls.
|
||||
return (unfiltered instanceof SetMultimap) ? Collections.<V>emptySet() : Collections.<V>emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
entries().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> get(final K key) {
|
||||
return filterCollection(unfiltered.get(key), new ValuePredicate(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<Entry<K, V>> createEntries() {
|
||||
return filterCollection(unfiltered.entries(), predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<V> createValues() {
|
||||
return new FilteredMultimapValues<K, V>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
Iterator<Entry<K, V>> entryIterator() {
|
||||
throw new AssertionError("should never be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<K, Collection<V>> createAsMap() {
|
||||
return new AsMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return asMap().keySet();
|
||||
}
|
||||
|
||||
boolean removeEntriesIf(Predicate<? super Entry<K, Collection<V>>> predicate) {
|
||||
Iterator<Entry<K, Collection<V>>> entryIterator = unfiltered.asMap().entrySet().iterator();
|
||||
boolean changed = false;
|
||||
while (entryIterator.hasNext()) {
|
||||
Entry<K, Collection<V>> entry = entryIterator.next();
|
||||
K key = entry.getKey();
|
||||
Collection<V> collection = filterCollection(entry.getValue(), new ValuePredicate(key));
|
||||
if (!collection.isEmpty() && predicate.apply(Maps.immutableEntry(key, collection))) {
|
||||
if (collection.size() == entry.getValue().size()) {
|
||||
entryIterator.remove();
|
||||
} else {
|
||||
collection.clear();
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
class AsMap extends ImprovedAbstractMap<K, Collection<V>> {
|
||||
@Override
|
||||
public boolean containsKey(@Nullable Object key) {
|
||||
return get(key) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
FilteredEntryMultimap.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> get(@Nullable Object key) {
|
||||
Collection<V> result = unfiltered.asMap().get(key);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings("unchecked") // key is equal to a K, if not a K itself
|
||||
K k = (K) key;
|
||||
result = filterCollection(result, new ValuePredicate(k));
|
||||
return result.isEmpty() ? null : result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> remove(@Nullable Object key) {
|
||||
Collection<V> collection = unfiltered.asMap().get(key);
|
||||
if (collection == null) {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings("unchecked") // it's definitely equal to a K
|
||||
K k = (K) key;
|
||||
List<V> result = Lists.newArrayList();
|
||||
Iterator<V> itr = collection.iterator();
|
||||
while (itr.hasNext()) {
|
||||
V v = itr.next();
|
||||
if (satisfies(k, v)) {
|
||||
itr.remove();
|
||||
result.add(v);
|
||||
}
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
return null;
|
||||
} else if (unfiltered instanceof SetMultimap) {
|
||||
return Collections.unmodifiableSet(Sets.newLinkedHashSet(result));
|
||||
} else {
|
||||
return Collections.unmodifiableList(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<K> createKeySet() {
|
||||
return new Maps.KeySet<K, Collection<V>>(this) {
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return removeEntriesIf(Maps.<K>keyPredicateOnEntries(in(c)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return removeEntriesIf(Maps.<K>keyPredicateOnEntries(not(in(c))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(@Nullable Object o) {
|
||||
return AsMap.this.remove(o) != null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Entry<K, Collection<V>>> createEntrySet() {
|
||||
return new Maps.EntrySet<K, Collection<V>>() {
|
||||
@Override
|
||||
Map<K, Collection<V>> map() {
|
||||
return AsMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<K, Collection<V>>> iterator() {
|
||||
return new AbstractIterator<Entry<K, Collection<V>>>() {
|
||||
final Iterator<Entry<K, Collection<V>>> backingIterator = unfiltered.asMap().entrySet()
|
||||
.iterator();
|
||||
|
||||
@Override
|
||||
protected Entry<K, Collection<V>> computeNext() {
|
||||
while (backingIterator.hasNext()) {
|
||||
Entry<K, Collection<V>> entry = backingIterator.next();
|
||||
K key = entry.getKey();
|
||||
Collection<V> collection = filterCollection(entry.getValue(), new ValuePredicate(key));
|
||||
if (!collection.isEmpty()) {
|
||||
return Maps.immutableEntry(key, collection);
|
||||
}
|
||||
}
|
||||
return endOfData();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return removeEntriesIf(in(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return removeEntriesIf(not(in(c)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Iterators.size(iterator());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<Collection<V>> createValues() {
|
||||
return new Maps.Values<K, Collection<V>>(AsMap.this) {
|
||||
@Override
|
||||
public boolean remove(@Nullable Object o) {
|
||||
if (o instanceof Collection) {
|
||||
Collection<?> c = (Collection<?>) o;
|
||||
Iterator<Entry<K, Collection<V>>> entryIterator = unfiltered.asMap().entrySet().iterator();
|
||||
while (entryIterator.hasNext()) {
|
||||
Entry<K, Collection<V>> entry = entryIterator.next();
|
||||
K key = entry.getKey();
|
||||
Collection<V> collection = filterCollection(entry.getValue(), new ValuePredicate(key));
|
||||
if (!collection.isEmpty() && c.equals(collection)) {
|
||||
if (collection.size() == entry.getValue().size()) {
|
||||
entryIterator.remove();
|
||||
} else {
|
||||
collection.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return removeEntriesIf(Maps.<Collection<V>>valuePredicateOnEntries(in(c)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return removeEntriesIf(Maps.<Collection<V>>valuePredicateOnEntries(not(in(c))));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Multiset<K> createKeys() {
|
||||
return new Keys();
|
||||
}
|
||||
|
||||
class Keys extends Multimaps.Keys<K, V> {
|
||||
Keys() {
|
||||
super(FilteredEntryMultimap.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remove(@Nullable Object key, int occurrences) {
|
||||
checkNonnegative(occurrences, "occurrences");
|
||||
if (occurrences == 0) {
|
||||
return count(key);
|
||||
}
|
||||
Collection<V> collection = unfiltered.asMap().get(key);
|
||||
if (collection == null) {
|
||||
return 0;
|
||||
}
|
||||
@SuppressWarnings("unchecked") // key is equal to a K, if not a K itself
|
||||
K k = (K) key;
|
||||
int oldCount = 0;
|
||||
Iterator<V> itr = collection.iterator();
|
||||
while (itr.hasNext()) {
|
||||
V v = itr.next();
|
||||
if (satisfies(k, v)) {
|
||||
oldCount++;
|
||||
if (oldCount <= occurrences) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return oldCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Multiset.Entry<K>> entrySet() {
|
||||
return new Multisets.EntrySet<K>() {
|
||||
|
||||
@Override
|
||||
Multiset<K> multiset() {
|
||||
return Keys.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Multiset.Entry<K>> iterator() {
|
||||
return Keys.this.entryIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return FilteredEntryMultimap.this.keySet().size();
|
||||
}
|
||||
|
||||
private boolean removeEntriesIf(final Predicate<? super Multiset.Entry<K>> predicate) {
|
||||
return FilteredEntryMultimap.this.removeEntriesIf(new Predicate<Map.Entry<K, Collection<V>>>() {
|
||||
@Override
|
||||
public boolean apply(Map.Entry<K, Collection<V>> entry) {
|
||||
return predicate.apply(Multisets.immutableEntry(entry.getKey(), entry.getValue().size()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return removeEntriesIf(in(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return removeEntriesIf(not(in(c)));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Multimaps#filterEntries(SetMultimap, Predicate)}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
final class FilteredEntrySetMultimap<K, V> extends FilteredEntryMultimap<K, V> implements FilteredSetMultimap<K, V> {
|
||||
|
||||
FilteredEntrySetMultimap(SetMultimap<K, V> unfiltered, Predicate<? super Entry<K, V>> predicate) {
|
||||
super(unfiltered, predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetMultimap<K, V> unfiltered() {
|
||||
return (SetMultimap<K, V>) unfiltered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> get(K key) {
|
||||
return (Set<V>) super.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> removeAll(Object key) {
|
||||
return (Set<V>) super.removeAll(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> replaceValues(K key, Iterable<? extends V> values) {
|
||||
return (Set<V>) super.replaceValues(key, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Entry<K, V>> createEntries() {
|
||||
return Sets.filter(unfiltered().entries(), entryPredicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entries() {
|
||||
return (Set<Entry<K, V>>) super.entries();
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Multimaps#filterKeys(ListMultimap, Predicate)}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
final class FilteredKeyListMultimap<K, V> extends FilteredKeyMultimap<K, V> implements ListMultimap<K, V> {
|
||||
FilteredKeyListMultimap(ListMultimap<K, V> unfiltered, Predicate<? super K> keyPredicate) {
|
||||
super(unfiltered, keyPredicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListMultimap<K, V> unfiltered() {
|
||||
return (ListMultimap<K, V>) super.unfiltered();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> get(K key) {
|
||||
return (List<V>) super.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> removeAll(@Nullable Object key) {
|
||||
return (List<V>) super.removeAll(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> replaceValues(K key, Iterable<? extends V> values) {
|
||||
return (List<V>) super.replaceValues(key, values);
|
||||
}
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkPositionIndex;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Multimaps#filterKeys(Multimap, Predicate)}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
class FilteredKeyMultimap<K, V> extends AbstractMultimap<K, V> implements FilteredMultimap<K, V> {
|
||||
final Multimap<K, V> unfiltered;
|
||||
final Predicate<? super K> keyPredicate;
|
||||
|
||||
FilteredKeyMultimap(Multimap<K, V> unfiltered, Predicate<? super K> keyPredicate) {
|
||||
this.unfiltered = checkNotNull(unfiltered);
|
||||
this.keyPredicate = checkNotNull(keyPredicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multimap<K, V> unfiltered() {
|
||||
return unfiltered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<? super Entry<K, V>> entryPredicate() {
|
||||
return Maps.keyPredicateOnEntries(keyPredicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
int size = 0;
|
||||
for (Collection<V> collection : asMap().values()) {
|
||||
size += collection.size();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(@Nullable Object key) {
|
||||
if (unfiltered.containsKey(key)) {
|
||||
@SuppressWarnings("unchecked") // k is equal to a K, if not one itself
|
||||
K k = (K) key;
|
||||
return keyPredicate.apply(k);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> removeAll(Object key) {
|
||||
return containsKey(key) ? unfiltered.removeAll(key) : unmodifiableEmptyCollection();
|
||||
}
|
||||
|
||||
Collection<V> unmodifiableEmptyCollection() {
|
||||
if (unfiltered instanceof SetMultimap) {
|
||||
return ImmutableSet.of();
|
||||
} else {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
keySet().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<K> createKeySet() {
|
||||
return Sets.filter(unfiltered.keySet(), keyPredicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> get(K key) {
|
||||
if (keyPredicate.apply(key)) {
|
||||
return unfiltered.get(key);
|
||||
} else if (unfiltered instanceof SetMultimap) {
|
||||
return new AddRejectingSet<K, V>(key);
|
||||
} else {
|
||||
return new AddRejectingList<K, V>(key);
|
||||
}
|
||||
}
|
||||
|
||||
static class AddRejectingSet<K, V> extends ForwardingSet<V> {
|
||||
final K key;
|
||||
|
||||
AddRejectingSet(K key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(V element) {
|
||||
throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends V> collection) {
|
||||
checkNotNull(collection);
|
||||
throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<V> delegate() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
static class AddRejectingList<K, V> extends ForwardingList<V> {
|
||||
final K key;
|
||||
|
||||
AddRejectingList(K key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(V v) {
|
||||
add(0, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends V> collection) {
|
||||
addAll(0, collection);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, V element) {
|
||||
checkPositionIndex(index, 0);
|
||||
throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends V> elements) {
|
||||
checkNotNull(elements);
|
||||
checkPositionIndex(index, 0);
|
||||
throw new IllegalArgumentException("Key does not satisfy predicate: " + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<V> delegate() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Iterator<Entry<K, V>> entryIterator() {
|
||||
throw new AssertionError("should never be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<Entry<K, V>> createEntries() {
|
||||
return new Entries();
|
||||
}
|
||||
|
||||
class Entries extends ForwardingCollection<Entry<K, V>> {
|
||||
@Override
|
||||
protected Collection<Entry<K, V>> delegate() {
|
||||
return Collections2.filter(unfiltered.entries(), entryPredicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean remove(@Nullable Object o) {
|
||||
if (o instanceof Entry) {
|
||||
Entry<?, ?> entry = (Entry<?, ?>) o;
|
||||
if (unfiltered.containsKey(entry.getKey())
|
||||
// if this holds, then we know entry.getKey() is a K
|
||||
&& keyPredicate.apply((K) entry.getKey())) {
|
||||
return unfiltered.remove(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Collection<V> createValues() {
|
||||
return new FilteredMultimapValues<K, V>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<K, Collection<V>> createAsMap() {
|
||||
return Maps.filterKeys(unfiltered.asMap(), keyPredicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
Multiset<K> createKeys() {
|
||||
return Multisets.filter(unfiltered.keys(), keyPredicate);
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Multimaps#filterKeys(SetMultimap, Predicate)}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
final class FilteredKeySetMultimap<K, V> extends FilteredKeyMultimap<K, V> implements FilteredSetMultimap<K, V> {
|
||||
|
||||
FilteredKeySetMultimap(SetMultimap<K, V> unfiltered, Predicate<? super K> keyPredicate) {
|
||||
super(unfiltered, keyPredicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetMultimap<K, V> unfiltered() {
|
||||
return (SetMultimap<K, V>) unfiltered;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> get(K key) {
|
||||
return (Set<V>) super.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> removeAll(Object key) {
|
||||
return (Set<V>) super.removeAll(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> replaceValues(K key, Iterable<? extends V> values) {
|
||||
return (Set<V>) super.replaceValues(key, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entries() {
|
||||
return (Set<Entry<K, V>>) super.entries();
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Entry<K, V>> createEntries() {
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
class EntrySet extends Entries implements Set<Entry<K, V>> {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Sets.hashCodeImpl(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
return Sets.equalsImpl(this, o);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
* An interface for all filtered multimap types.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
interface FilteredMultimap<K, V> extends Multimap<K, V> {
|
||||
Multimap<K, V> unfiltered();
|
||||
|
||||
Predicate<? super Entry<K, V>> entryPredicate();
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
|
||||
/**
|
||||
* Implementation for {@link FilteredMultimap#values()}.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
final class FilteredMultimapValues<K, V> extends AbstractCollection<V> {
|
||||
private final FilteredMultimap<K, V> multimap;
|
||||
|
||||
FilteredMultimapValues(FilteredMultimap<K, V> multimap) {
|
||||
this.multimap = checkNotNull(multimap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return Maps.valueIterator(multimap.entries().iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object o) {
|
||||
return multimap.containsValue(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return multimap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(@Nullable Object o) {
|
||||
Predicate<? super Entry<K, V>> entryPredicate = multimap.entryPredicate();
|
||||
for (Iterator<Entry<K, V>> unfilteredItr = multimap.unfiltered().entries().iterator(); unfilteredItr
|
||||
.hasNext();) {
|
||||
Map.Entry<K, V> entry = unfilteredItr.next();
|
||||
if (entryPredicate.apply(entry) && Objects.equal(entry.getValue(), o)) {
|
||||
unfilteredItr.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return Iterables.removeIf(multimap.unfiltered().entries(),
|
||||
// explicit <Entry<K, V>> is required to build with JDK6
|
||||
Predicates.<Entry<K, V>>and(multimap.entryPredicate(),
|
||||
Maps.<V>valuePredicateOnEntries(Predicates.in(c))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return Iterables.removeIf(multimap.unfiltered().entries(),
|
||||
// explicit <Entry<K, V>> is required to build with JDK6
|
||||
Predicates.<Entry<K, V>>and(multimap.entryPredicate(),
|
||||
Maps.<V>valuePredicateOnEntries(Predicates.not(Predicates.in(c)))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
multimap.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A supertype for filtered {@link SetMultimap} implementations.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible
|
||||
interface FilteredSetMultimap<K, V> extends FilteredMultimap<K, V>, SetMultimap<K, V> {
|
||||
@Override
|
||||
SetMultimap<K, V> unfiltered();
|
||||
}
|
514
sources/main/java/com/google/common/collect/FluentIterable.java
Normal file
514
sources/main/java/com/google/common/collect/FluentIterable.java
Normal file
@ -0,0 +1,514 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
* {@code FluentIterable} provides a rich interface for manipulating
|
||||
* {@code Iterable} instances in a chained fashion. A {@code FluentIterable} can
|
||||
* be created from an {@code Iterable}, or from a set of elements. The following
|
||||
* types of methods are provided on {@code FluentIterable}:
|
||||
* <ul>
|
||||
* <li>chained methods which return a new {@code FluentIterable} based in some
|
||||
* way on the contents of the current one (for example {@link #transform})
|
||||
* <li>conversion methods which copy the {@code FluentIterable}'s contents into
|
||||
* a new collection or array (for example {@link #toList})
|
||||
* <li>element extraction methods which facilitate the retrieval of certain
|
||||
* elements (for example {@link #last})
|
||||
* <li>query methods which answer questions about the {@code FluentIterable}'s
|
||||
* contents (for example {@link #anyMatch})
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Here is an example that merges the lists returned by two separate database
|
||||
* calls, transforms it by invoking {@code toString()} on each element, and
|
||||
* returns the first 10 elements as an {@code ImmutableList}:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
*
|
||||
* FluentIterable
|
||||
* .from(database.getClientList())
|
||||
* .filter(activeInLastMonth())
|
||||
* .transform(Functions.toStringFunction())
|
||||
* .limit(10)
|
||||
* .toList();}
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Anything which can be done using {@code FluentIterable} could be done in a
|
||||
* different fashion (often with {@link Iterables}), however the use of
|
||||
* {@code FluentIterable} makes many sets of operations significantly more
|
||||
* concise.
|
||||
*
|
||||
* @author Marcin Mikosik
|
||||
* @since 12.0
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
public abstract class FluentIterable<E> implements Iterable<E> {
|
||||
// We store 'iterable' and use it instead of 'this' to allow Iterables to
|
||||
// perform instanceof
|
||||
// checks on the _original_ iterable when FluentIterable.from is used.
|
||||
private final Iterable<E> iterable;
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected FluentIterable() {
|
||||
this.iterable = this;
|
||||
}
|
||||
|
||||
FluentIterable(Iterable<E> iterable) {
|
||||
this.iterable = checkNotNull(iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fluent iterable that wraps {@code iterable}, or {@code iterable}
|
||||
* itself if it is already a {@code FluentIterable}.
|
||||
*/
|
||||
public static <E> FluentIterable<E> from(final Iterable<E> iterable) {
|
||||
return (iterable instanceof FluentIterable) ? (FluentIterable<E>) iterable : new FluentIterable<E>(iterable) {
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return iterable.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a fluent iterable from another fluent iterable. This is obviously
|
||||
* never necessary, but is intended to help call out cases where one migration
|
||||
* from {@code Iterable} to {@code FluentIterable} has obviated the need to
|
||||
* explicitly convert to a {@code FluentIterable}.
|
||||
*
|
||||
* @deprecated instances of {@code FluentIterable} don't need to be converted to
|
||||
* {@code FluentIterable}
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E> FluentIterable<E> from(FluentIterable<E> iterable) {
|
||||
return checkNotNull(iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this fluent iterable, with the format
|
||||
* {@code [e1, e2, ..., en]}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Iterables.toString(iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this fluent iterable.
|
||||
*/
|
||||
public final int size() {
|
||||
return Iterables.size(iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this fluent iterable contains any object for which
|
||||
* {@code equals(element)} is true.
|
||||
*/
|
||||
public final boolean contains(@Nullable Object element) {
|
||||
return Iterables.contains(iterable, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fluent iterable whose {@code Iterator} cycles indefinitely over the
|
||||
* elements of this fluent iterable.
|
||||
*
|
||||
* <p>
|
||||
* That iterator supports {@code remove()} if {@code iterable.iterator()} does.
|
||||
* After {@code remove()} is called, subsequent cycles omit the removed element,
|
||||
* which is no longer in this fluent iterable. The iterator's {@code hasNext()}
|
||||
* method returns {@code true} until this fluent iterable is empty.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> Typical uses of the resulting iterator may produce an
|
||||
* infinite loop. You should use an explicit {@code break} or be certain that
|
||||
* you will eventually remove all the elements.
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public final FluentIterable<E> cycle() {
|
||||
return from(Iterables.cycle(iterable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the elements from this fluent iterable that satisfy a predicate. The
|
||||
* resulting fluent iterable's iterator does not support {@code remove()}.
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public final FluentIterable<E> filter(Predicate<? super E> predicate) {
|
||||
return from(Iterables.filter(iterable, predicate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the elements from this fluent iterable that are instances of class
|
||||
* {@code type}.
|
||||
*
|
||||
* @param type the type of elements desired
|
||||
*/
|
||||
@GwtIncompatible("Class.isInstance")
|
||||
@CheckReturnValue
|
||||
public final <T> FluentIterable<T> filter(Class<T> type) {
|
||||
return from(Iterables.filter(iterable, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if any element in this fluent iterable satisfies the
|
||||
* predicate.
|
||||
*/
|
||||
public final boolean anyMatch(Predicate<? super E> predicate) {
|
||||
return Iterables.any(iterable, predicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if every element in this fluent iterable satisfies the
|
||||
* predicate. If this fluent iterable is empty, {@code true} is returned.
|
||||
*/
|
||||
public final boolean allMatch(Predicate<? super E> predicate) {
|
||||
return Iterables.all(iterable, predicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the first element in this fluent
|
||||
* iterable that satisfies the given predicate, if such an element exists.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> avoid using a {@code predicate} that matches {@code null}. If
|
||||
* {@code null} is matched in this fluent iterable, a
|
||||
* {@link NullPointerException} will be thrown.
|
||||
*/
|
||||
public final Optional<E> firstMatch(Predicate<? super E> predicate) {
|
||||
return Iterables.tryFind(iterable, predicate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fluent iterable that applies {@code function} to each element of
|
||||
* this fluent iterable.
|
||||
*
|
||||
* <p>
|
||||
* The returned fluent iterable's iterator supports {@code remove()} if this
|
||||
* iterable's iterator does. After a successful {@code remove()} call, this
|
||||
* fluent iterable no longer contains the corresponding element.
|
||||
*/
|
||||
public final <T> FluentIterable<T> transform(Function<? super E, T> function) {
|
||||
return from(Iterables.transform(iterable, function));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies {@code function} to each element of this fluent iterable and returns
|
||||
* a fluent iterable with the concatenated combination of results.
|
||||
* {@code function} returns an Iterable of results.
|
||||
*
|
||||
* <p>
|
||||
* The returned fluent iterable's iterator supports {@code remove()} if this
|
||||
* function-returned iterables' iterator does. After a successful
|
||||
* {@code remove()} call, the returned fluent iterable no longer contains the
|
||||
* corresponding element.
|
||||
*
|
||||
* @since 13.0 (required {@code Function<E, Iterable<T>>} until 14.0)
|
||||
*/
|
||||
public <T> FluentIterable<T> transformAndConcat(Function<? super E, ? extends Iterable<? extends T>> function) {
|
||||
return from(Iterables.concat(transform(function)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the first element in this fluent
|
||||
* iterable. If the iterable is empty, {@code Optional.absent()} is returned.
|
||||
*
|
||||
* @throws NullPointerException if the first element is null; if this is a
|
||||
* possibility, use {@code iterator().next()} or
|
||||
* {@link Iterables#getFirst} instead.
|
||||
*/
|
||||
public final Optional<E> first() {
|
||||
Iterator<E> iterator = iterable.iterator();
|
||||
return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.<E>absent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Optional} containing the last element in this fluent
|
||||
* iterable. If the iterable is empty, {@code Optional.absent()} is returned.
|
||||
*
|
||||
* @throws NullPointerException if the last element is null; if this is a
|
||||
* possibility, use {@link Iterables#getLast}
|
||||
* instead.
|
||||
*/
|
||||
public final Optional<E> last() {
|
||||
// Iterables#getLast was inlined here so we don't have to throw/catch a NSEE
|
||||
|
||||
// TODO(kevinb): Support a concurrently modified collection?
|
||||
if (iterable instanceof List) {
|
||||
List<E> list = (List<E>) iterable;
|
||||
if (list.isEmpty()) {
|
||||
return Optional.absent();
|
||||
}
|
||||
return Optional.of(list.get(list.size() - 1));
|
||||
}
|
||||
Iterator<E> iterator = iterable.iterator();
|
||||
if (!iterator.hasNext()) {
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(kevinb): consider whether this "optimization" is worthwhile. Users with
|
||||
* SortedSets tend to know they are SortedSets and probably would not call this
|
||||
* method.
|
||||
*/
|
||||
if (iterable instanceof SortedSet) {
|
||||
SortedSet<E> sortedSet = (SortedSet<E>) iterable;
|
||||
return Optional.of(sortedSet.last());
|
||||
}
|
||||
|
||||
while (true) {
|
||||
E current = iterator.next();
|
||||
if (!iterator.hasNext()) {
|
||||
return Optional.of(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of this fluent iterable that skips its first
|
||||
* {@code numberToSkip} elements. If this fluent iterable contains fewer than
|
||||
* {@code numberToSkip} elements, the returned fluent iterable skips all of its
|
||||
* elements.
|
||||
*
|
||||
* <p>
|
||||
* Modifications to this fluent iterable before a call to {@code iterator()} are
|
||||
* reflected in the returned fluent iterable. That is, the its iterator skips
|
||||
* the first {@code numberToSkip} elements that exist when the iterator is
|
||||
* created, not when {@code skip()} is called.
|
||||
*
|
||||
* <p>
|
||||
* The returned fluent iterable's iterator supports {@code remove()} if the
|
||||
* {@code Iterator} of this fluent iterable supports it. Note that it is
|
||||
* <i>not</i> possible to delete the last skipped element by immediately calling
|
||||
* {@code remove()} on the returned fluent iterable's iterator, as the
|
||||
* {@code Iterator} contract states that a call to {@code * remove()} before a
|
||||
* call to {@code next()} will throw an {@link IllegalStateException}.
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public final FluentIterable<E> skip(int numberToSkip) {
|
||||
return from(Iterables.skip(iterable, numberToSkip));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fluent iterable with the first {@code size} elements of this fluent
|
||||
* iterable. If this fluent iterable does not contain that many elements, the
|
||||
* returned fluent iterable will have the same behavior as this fluent iterable.
|
||||
* The returned fluent iterable's iterator supports {@code remove()} if this
|
||||
* fluent iterable's iterator does.
|
||||
*
|
||||
* @param size the maximum number of elements in the returned fluent iterable
|
||||
* @throws IllegalArgumentException if {@code size} is negative
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public final FluentIterable<E> limit(int size) {
|
||||
return from(Iterables.limit(iterable, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this fluent iterable is empty.
|
||||
*/
|
||||
public final boolean isEmpty() {
|
||||
return !iterable.iterator().hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code ImmutableList} containing all of the elements from this
|
||||
* fluent iterable in proper sequence.
|
||||
*
|
||||
* @since 14.0 (since 12.0 as {@code toImmutableList()}).
|
||||
*/
|
||||
public final ImmutableList<E> toList() {
|
||||
return ImmutableList.copyOf(iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code ImmutableList} containing all of the elements from this
|
||||
* {@code
|
||||
* FluentIterable} in the order specified by {@code comparator}. To produce an
|
||||
* {@code
|
||||
* ImmutableList} sorted by its natural ordering, use
|
||||
* {@code toSortedList(Ordering.natural())}.
|
||||
*
|
||||
* @param comparator the function by which to sort list elements
|
||||
* @throws NullPointerException if any element is null
|
||||
* @since 14.0 (since 13.0 as {@code toSortedImmutableList()}).
|
||||
*/
|
||||
@Beta
|
||||
public final ImmutableList<E> toSortedList(Comparator<? super E> comparator) {
|
||||
return Ordering.from(comparator).immutableSortedCopy(iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code ImmutableSet} containing all of the elements from this
|
||||
* fluent iterable with duplicates removed.
|
||||
*
|
||||
* @since 14.0 (since 12.0 as {@code toImmutableSet()}).
|
||||
*/
|
||||
public final ImmutableSet<E> toSet() {
|
||||
return ImmutableSet.copyOf(iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code ImmutableSortedSet} containing all of the elements from
|
||||
* this {@code
|
||||
* FluentIterable} in the order specified by {@code comparator}, with duplicates
|
||||
* (determined by {@code comparator.compare(x, y) == 0}) removed. To produce an
|
||||
* {@code ImmutableSortedSet} sorted by its natural ordering, use
|
||||
* {@code toSortedSet(Ordering.natural())}.
|
||||
*
|
||||
* @param comparator the function by which to sort set elements
|
||||
* @throws NullPointerException if any element is null
|
||||
* @since 14.0 (since 12.0 as {@code toImmutableSortedSet()}).
|
||||
*/
|
||||
public final ImmutableSortedSet<E> toSortedSet(Comparator<? super E> comparator) {
|
||||
return ImmutableSortedSet.copyOf(comparator, iterable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map for which the elements of this
|
||||
* {@code FluentIterable} are the keys in the same order, mapped to values by
|
||||
* the given function. If this iterable contains duplicate elements, the
|
||||
* returned map will contain each distinct element once in the order it first
|
||||
* appears.
|
||||
*
|
||||
* @throws NullPointerException if any element of this iterable is {@code null},
|
||||
* or if {@code
|
||||
* valueFunction} produces {@code null} for any key
|
||||
* @since 14.0
|
||||
*/
|
||||
public final <V> ImmutableMap<E, V> toMap(Function<? super E, V> valueFunction) {
|
||||
return Maps.toMap(iterable, valueFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an index {@code ImmutableListMultimap} that contains the results of
|
||||
* applying a specified function to each item in this {@code FluentIterable} of
|
||||
* values. Each element of this iterable will be stored as a value in the
|
||||
* resulting multimap, yielding a multimap with the same size as this iterable.
|
||||
* The key used to store that value in the multimap will be the result of
|
||||
* calling the function on that value. The resulting multimap is created as an
|
||||
* immutable snapshot. In the returned multimap, keys appear in the order they
|
||||
* are first encountered, and the values corresponding to each key appear in the
|
||||
* same order as they are encountered.
|
||||
*
|
||||
* @param keyFunction the function used to produce the key for each value
|
||||
* @throws NullPointerException if any of the following cases is true:
|
||||
* <ul>
|
||||
* <li>{@code keyFunction} is null
|
||||
* <li>An element in this fluent iterable is null
|
||||
* <li>{@code keyFunction} returns {@code null} for
|
||||
* any element of this iterable
|
||||
* </ul>
|
||||
* @since 14.0
|
||||
*/
|
||||
public final <K> ImmutableListMultimap<K, E> index(Function<? super E, K> keyFunction) {
|
||||
return Multimaps.index(iterable, keyFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map for which the {@link java.util.Map#values} are the
|
||||
* elements of this {@code FluentIterable} in the given order, and each key is
|
||||
* the product of invoking a supplied function on its corresponding value.
|
||||
*
|
||||
* @param keyFunction the function used to produce the key for each value
|
||||
* @throws IllegalArgumentException if {@code keyFunction} produces the same key
|
||||
* for more than one value in this fluent
|
||||
* iterable
|
||||
* @throws NullPointerException if any element of this fluent iterable is
|
||||
* null, or if {@code keyFunction} produces
|
||||
* {@code null} for any value
|
||||
* @since 14.0
|
||||
*/
|
||||
public final <K> ImmutableMap<K, E> uniqueIndex(Function<? super E, K> keyFunction) {
|
||||
return Maps.uniqueIndex(iterable, keyFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the elements from this fluent iterable in
|
||||
* iteration order.
|
||||
*
|
||||
* @param type the type of the elements
|
||||
* @return a newly-allocated array into which all the elements of this fluent
|
||||
* iterable have been copied
|
||||
*/
|
||||
@GwtIncompatible("Array.newArray(Class, int)")
|
||||
public final E[] toArray(Class<E> type) {
|
||||
return Iterables.toArray(iterable, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all the elements from this fluent iterable to {@code collection}. This
|
||||
* is equivalent to calling {@code Iterables.addAll(collection, this)}.
|
||||
*
|
||||
* @param collection the collection to copy elements to
|
||||
* @return {@code collection}, for convenience
|
||||
* @since 14.0
|
||||
*/
|
||||
public final <C extends Collection<? super E>> C copyInto(C collection) {
|
||||
checkNotNull(collection);
|
||||
if (iterable instanceof Collection) {
|
||||
collection.addAll(Collections2.cast(iterable));
|
||||
} else {
|
||||
for (E item : iterable) {
|
||||
collection.add(item);
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element at the specified position in this fluent iterable.
|
||||
*
|
||||
* @param position position of the element to return
|
||||
* @return the element at the specified position in this fluent iterable
|
||||
* @throws IndexOutOfBoundsException if {@code position} is negative or greater
|
||||
* than or equal to the size of this fluent
|
||||
* iterable
|
||||
*/
|
||||
public final E get(int position) {
|
||||
return Iterables.get(iterable, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that transforms {@code Iterable<E>} into a fluent iterable.
|
||||
*/
|
||||
private static class FromIterableFunction<E> implements Function<Iterable<E>, FluentIterable<E>> {
|
||||
@Override
|
||||
public FluentIterable<E> apply(Iterable<E> fromObject) {
|
||||
return FluentIterable.from(fromObject);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* A collection which forwards all its method calls to another collection.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing collection as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> The methods of {@code ForwardingCollection} forward
|
||||
* <b>indiscriminately</b> to the methods of the delegate. For example,
|
||||
* overriding {@link #add} alone <b>will not</b> change the behavior of
|
||||
* {@link #addAll}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code addAll} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardAddAll} method.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods are not guaranteed to be thread-safe, even when
|
||||
* all of the methods that they depend on are thread-safe.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingCollection<E> extends ForwardingObject implements Collection<E> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingCollection() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Collection<E> delegate();
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return delegate().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> collection) {
|
||||
return delegate().removeAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object object) {
|
||||
return delegate().contains(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
return delegate().add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object object) {
|
||||
return delegate().remove(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> collection) {
|
||||
return delegate().containsAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> collection) {
|
||||
return delegate().addAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> collection) {
|
||||
return delegate().retainAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
delegate().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return delegate().toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] array) {
|
||||
return delegate().toArray(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #contains} in terms of {@link #iterator}. If
|
||||
* you override {@link #iterator}, you may wish to override {@link #contains} to
|
||||
* forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardContains(@Nullable Object object) {
|
||||
return Iterators.contains(iterator(), object);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #containsAll} in terms of {@link #contains} .
|
||||
* If you override {@link #contains}, you may wish to override
|
||||
* {@link #containsAll} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardContainsAll(Collection<?> collection) {
|
||||
return Collections2.containsAllImpl(this, collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #addAll} in terms of {@link #add}. If you
|
||||
* override {@link #add}, you may wish to override {@link #addAll} to forward to
|
||||
* this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardAddAll(Collection<? extends E> collection) {
|
||||
return Iterators.addAll(this, collection.iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #remove} in terms of {@link #iterator}, using
|
||||
* the iterator's {@code remove} method. If you override {@link #iterator}, you
|
||||
* may wish to override {@link #remove} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardRemove(@Nullable Object object) {
|
||||
Iterator<E> iterator = iterator();
|
||||
while (iterator.hasNext()) {
|
||||
if (Objects.equal(iterator.next(), object)) {
|
||||
iterator.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #removeAll} in terms of {@link #iterator},
|
||||
* using the iterator's {@code remove} method. If you override
|
||||
* {@link #iterator}, you may wish to override {@link #removeAll} to forward to
|
||||
* this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardRemoveAll(Collection<?> collection) {
|
||||
return Iterators.removeAll(iterator(), collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #retainAll} in terms of {@link #iterator},
|
||||
* using the iterator's {@code remove} method. If you override
|
||||
* {@link #iterator}, you may wish to override {@link #retainAll} to forward to
|
||||
* this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardRetainAll(Collection<?> collection) {
|
||||
return Iterators.retainAll(iterator(), collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #clear} in terms of {@link #iterator}, using
|
||||
* the iterator's {@code remove} method. If you override {@link #iterator}, you
|
||||
* may wish to override {@link #clear} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected void standardClear() {
|
||||
Iterators.clear(iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #isEmpty} as {@code !iterator().hasNext}. If
|
||||
* you override {@link #isEmpty}, you may wish to override {@link #isEmpty} to
|
||||
* forward to this implementation. Alternately, it may be more efficient to
|
||||
* implement {@code isEmpty} as {@code size() == 0}.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardIsEmpty() {
|
||||
return !iterator().hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toString} in terms of {@link #iterator}. If
|
||||
* you override {@link #iterator}, you may wish to override {@link #toString} to
|
||||
* forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected String standardToString() {
|
||||
return Collections2.toStringImpl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toArray()} in terms of
|
||||
* {@link #toArray(Object[])}. If you override {@link #toArray(Object[])}, you
|
||||
* may wish to override {@link #toArray} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected Object[] standardToArray() {
|
||||
Object[] newArray = new Object[size()];
|
||||
return toArray(newArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toArray(Object[])} in terms of {@link #size}
|
||||
* and {@link #iterator}. If you override either of these methods, you may wish
|
||||
* to override {@link #toArray} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected <T> T[] standardToArray(T[] array) {
|
||||
return ObjectArrays.toArrayImpl(this, array);
|
||||
}
|
||||
}
|
132
sources/main/java/com/google/common/collect/ForwardingDeque.java
Normal file
132
sources/main/java/com/google/common/collect/ForwardingDeque.java
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* A deque which forwards all its method calls to another deque. Subclasses
|
||||
* should override one or more methods to modify the behavior of the backing
|
||||
* deque as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> The methods of {@code ForwardingDeque} forward
|
||||
* <b>indiscriminately</b> to the methods of the delegate. For example,
|
||||
* overriding {@link #add} alone <b>will not</b> change the behavior of
|
||||
* {@link #offer} which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code offer} as well.
|
||||
*
|
||||
* @author Kurt Alfred Kluever
|
||||
* @since 12.0
|
||||
*/
|
||||
public abstract class ForwardingDeque<E> extends ForwardingQueue<E> implements Deque<E> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingDeque() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Deque<E> delegate();
|
||||
|
||||
@Override
|
||||
public void addFirst(E e) {
|
||||
delegate().addFirst(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLast(E e) {
|
||||
delegate().addLast(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> descendingIterator() {
|
||||
return delegate().descendingIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getFirst() {
|
||||
return delegate().getFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E getLast() {
|
||||
return delegate().getLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offerFirst(E e) {
|
||||
return delegate().offerFirst(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offerLast(E e) {
|
||||
return delegate().offerLast(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peekFirst() {
|
||||
return delegate().peekFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peekLast() {
|
||||
return delegate().peekLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pollFirst() {
|
||||
return delegate().pollFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pollLast() {
|
||||
return delegate().pollLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pop() {
|
||||
return delegate().pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(E e) {
|
||||
delegate().push(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E removeFirst() {
|
||||
return delegate().removeFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E removeLast() {
|
||||
return delegate().removeLast();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeFirstOccurrence(Object o) {
|
||||
return delegate().removeFirstOccurrence(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeLastOccurrence(Object o) {
|
||||
return delegate().removeLastOccurrence(o);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 com.google.common.collect;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Dummy class that makes the GWT serialization policy happy. It isn't used on
|
||||
* the server-side.
|
||||
*
|
||||
* @author Hayward Chan
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
class ForwardingImmutableCollection {
|
||||
private ForwardingImmutableCollection() {
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Unused stub class, unreferenced under Java and manually emulated under GWT.
|
||||
*
|
||||
* @author Chris Povirk
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
abstract class ForwardingImmutableList<E> {
|
||||
private ForwardingImmutableList() {
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Unused stub class, unreferenced under Java and manually emulated under GWT.
|
||||
*
|
||||
* @author Chris Povirk
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
abstract class ForwardingImmutableMap<K, V> {
|
||||
private ForwardingImmutableMap() {
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Unused stub class, unreferenced under Java and manually emulated under GWT.
|
||||
*
|
||||
* @author Chris Povirk
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
abstract class ForwardingImmutableSet<E> {
|
||||
private ForwardingImmutableSet() {
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* An iterator which forwards all its method calls to another iterator.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing iterator as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingIterator<T> extends ForwardingObject implements Iterator<T> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingIterator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Iterator<T> delegate();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return delegate().hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return delegate().next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
delegate().remove();
|
||||
}
|
||||
}
|
247
sources/main/java/com/google/common/collect/ForwardingList.java
Normal file
247
sources/main/java/com/google/common/collect/ForwardingList.java
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A list which forwards all its method calls to another list. Subclasses should
|
||||
* override one or more methods to modify the behavior of the backing list as
|
||||
* desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* This class does not implement {@link net.lax1dude.eaglercraft.v1_8.RandomAccess}. If the delegate
|
||||
* supports random access, the {@code ForwardingList} subclass should implement
|
||||
* the {@code RandomAccess} interface.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> The methods of {@code ForwardingList} forward
|
||||
* <b>indiscriminately</b> to the methods of the delegate. For example,
|
||||
* overriding {@link #add} alone <b>will not</b> change the behavior of
|
||||
* {@link #addAll}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code addAll} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardAddAll} method.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods and any collection views they return are not
|
||||
* guaranteed to be thread-safe, even when all of the methods that they depend
|
||||
* on are thread-safe.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingList<E> extends ForwardingCollection<E> implements List<E> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingList() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract List<E> delegate();
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
delegate().add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends E> elements) {
|
||||
return delegate().addAll(index, elements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
return delegate().get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object element) {
|
||||
return delegate().indexOf(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object element) {
|
||||
return delegate().lastIndexOf(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<E> listIterator() {
|
||||
return delegate().listIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator<E> listIterator(int index) {
|
||||
return delegate().listIterator(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
return delegate().remove(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
return delegate().set(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<E> subList(int fromIndex, int toIndex) {
|
||||
return delegate().subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return object == this || delegate().equals(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #add(Object)}, in terms of
|
||||
* {@link #add(int, Object)}. If you override {@link #add(int, Object)}, you may
|
||||
* wish to override {@link #add(Object)} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardAdd(E element) {
|
||||
add(size(), element);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #addAll(int, Collection)}, in
|
||||
* terms of the {@code add} method of {@link #listIterator(int)}. If you
|
||||
* override {@link #listIterator(int)}, you may wish to override
|
||||
* {@link #addAll(int, Collection)} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardAddAll(int index, Iterable<? extends E> elements) {
|
||||
return Lists.addAllImpl(this, index, elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #indexOf}, in terms of
|
||||
* {@link #listIterator()}. If you override {@link #listIterator()}, you may
|
||||
* wish to override {@link #indexOf} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected int standardIndexOf(@Nullable Object element) {
|
||||
return Lists.indexOfImpl(this, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #lastIndexOf}, in terms of
|
||||
* {@link #listIterator(int)}. If you override {@link #listIterator(int)}, you
|
||||
* may wish to override {@link #lastIndexOf} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected int standardLastIndexOf(@Nullable Object element) {
|
||||
return Lists.lastIndexOfImpl(this, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #iterator}, in terms of
|
||||
* {@link #listIterator()}. If you override {@link #listIterator()}, you may
|
||||
* wish to override {@link #iterator} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected Iterator<E> standardIterator() {
|
||||
return listIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #listIterator()}, in terms of
|
||||
* {@link #listIterator(int)}. If you override {@link #listIterator(int)}, you
|
||||
* may wish to override {@link #listIterator()} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected ListIterator<E> standardListIterator() {
|
||||
return listIterator(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #listIterator(int)}, in terms of
|
||||
* {@link #size}, {@link #get(int)}, {@link #set(int, Object)},
|
||||
* {@link #add(int, Object)}, and {@link #remove(int)}. If you override any of
|
||||
* these methods, you may wish to override {@link #listIterator(int)} to forward
|
||||
* to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected ListIterator<E> standardListIterator(int start) {
|
||||
return Lists.listIteratorImpl(this, start);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #subList(int, int)}. If you
|
||||
* override any other methods, you may wish to override
|
||||
* {@link #subList(int, int)} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected List<E> standardSubList(int fromIndex, int toIndex) {
|
||||
return Lists.subListImpl(this, fromIndex, toIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #equals(Object)} in terms of {@link #size}
|
||||
* and {@link #iterator}. If you override either of those methods, you may wish
|
||||
* to override {@link #equals(Object)} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected boolean standardEquals(@Nullable Object object) {
|
||||
return Lists.equalsImpl(this, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #hashCode} in terms of {@link #iterator}. If
|
||||
* you override {@link #iterator}, you may wish to override {@link #hashCode} to
|
||||
* forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected int standardHashCode() {
|
||||
return Lists.hashCodeImpl(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A list iterator which forwards all its method calls to another list iterator.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing iterator as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingListIterator<E> extends ForwardingIterator<E> implements ListIterator<E> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingListIterator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract ListIterator<E> delegate();
|
||||
|
||||
@Override
|
||||
public void add(E element) {
|
||||
delegate().add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return delegate().hasPrevious();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextIndex() {
|
||||
return delegate().nextIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E previous() {
|
||||
return delegate().previous();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
return delegate().previousIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(E element) {
|
||||
delegate().set(element);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 com.google.common.collect;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A list multimap which forwards all its method calls to another list multimap.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing multimap as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* @author Kurt Alfred Kluever
|
||||
* @since 3.0
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingListMultimap<K, V> extends ForwardingMultimap<K, V> implements ListMultimap<K, V> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingListMultimap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract ListMultimap<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public List<V> get(@Nullable K key) {
|
||||
return delegate().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> removeAll(@Nullable Object key) {
|
||||
return delegate().removeAll(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> replaceValues(K key, Iterable<? extends V> values) {
|
||||
return delegate().replaceValues(key, values);
|
||||
}
|
||||
}
|
319
sources/main/java/com/google/common/collect/ForwardingMap.java
Normal file
319
sources/main/java/com/google/common/collect/ForwardingMap.java
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* A map which forwards all its method calls to another map. Subclasses should
|
||||
* override one or more methods to modify the behavior of the backing map as
|
||||
* desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <i>Warning:</i> The methods of {@code ForwardingMap} forward
|
||||
* <i>indiscriminately</i> to the methods of the delegate. For example,
|
||||
* overriding {@link #put} alone <i>will not</i> change the behavior of
|
||||
* {@link #putAll}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code putAll} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardPutAll} method.
|
||||
*
|
||||
* <p>
|
||||
* Each of the {@code standard} methods, where appropriate, use
|
||||
* {@link Objects#equal} to test equality for both keys and values. This may not
|
||||
* be the desired behavior for map implementations that use non-standard notions
|
||||
* of key equality, such as a {@code SortedMap} whose comparator is not
|
||||
* consistent with {@code equals}.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods and the collection views they return are not
|
||||
* guaranteed to be thread-safe, even when all of the methods that they depend
|
||||
* on are thread-safe.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Jared Levy
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingMap<K, V> extends ForwardingObject implements Map<K, V> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingMap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Map<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object object) {
|
||||
return delegate().remove(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
delegate().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(@Nullable Object key) {
|
||||
return delegate().containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@Nullable Object value) {
|
||||
return delegate().containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(@Nullable Object key) {
|
||||
return delegate().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
return delegate().put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> map) {
|
||||
delegate().putAll(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return delegate().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return delegate().values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return delegate().entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return object == this || delegate().equals(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #putAll(Map)} in terms of
|
||||
* {@link #put(Object, Object)}. If you override {@link #put(Object, Object)},
|
||||
* you may wish to override {@link #putAll(Map)} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected void standardPutAll(Map<? extends K, ? extends V> map) {
|
||||
Maps.putAllImpl(this, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible, albeit inefficient, definition of {@link #remove} in terms of the
|
||||
* {@code iterator} method of {@link #entrySet}. If you override
|
||||
* {@link #entrySet}, you may wish to override {@link #remove} to forward to
|
||||
* this implementation.
|
||||
*
|
||||
* <p>
|
||||
* Alternately, you may wish to override {@link #remove} with {@code
|
||||
* keySet().remove}, assuming that approach would not lead to an infinite loop.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected V standardRemove(@Nullable Object key) {
|
||||
Iterator<Entry<K, V>> entryIterator = entrySet().iterator();
|
||||
while (entryIterator.hasNext()) {
|
||||
Entry<K, V> entry = entryIterator.next();
|
||||
if (Objects.equal(entry.getKey(), key)) {
|
||||
V value = entry.getValue();
|
||||
entryIterator.remove();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #clear} in terms of the {@code iterator}
|
||||
* method of {@link #entrySet}. In many cases, you may wish to override
|
||||
* {@link #clear} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected void standardClear() {
|
||||
Iterators.clear(entrySet().iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link Map#keySet} in terms of the following
|
||||
* methods: {@link ForwardingMap#clear}, {@link ForwardingMap#containsKey},
|
||||
* {@link ForwardingMap#isEmpty}, {@link ForwardingMap#remove},
|
||||
* {@link ForwardingMap#size}, and the {@link Set#iterator} method of
|
||||
* {@link ForwardingMap#entrySet}. In many cases, you may wish to override
|
||||
* {@link ForwardingMap#keySet} to forward to this implementation or a subclass
|
||||
* thereof.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
@Beta
|
||||
protected class StandardKeySet extends Maps.KeySet<K, V> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardKeySet() {
|
||||
super(ForwardingMap.this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible, albeit inefficient, definition of {@link #containsKey} in terms
|
||||
* of the {@code iterator} method of {@link #entrySet}. If you override
|
||||
* {@link #entrySet}, you may wish to override {@link #containsKey} to forward
|
||||
* to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected boolean standardContainsKey(@Nullable Object key) {
|
||||
return Maps.containsKeyImpl(this, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link Map#values} in terms of the following
|
||||
* methods: {@link ForwardingMap#clear}, {@link ForwardingMap#containsValue},
|
||||
* {@link ForwardingMap#isEmpty}, {@link ForwardingMap#size}, and the
|
||||
* {@link Set#iterator} method of {@link ForwardingMap#entrySet}. In many cases,
|
||||
* you may wish to override {@link ForwardingMap#values} to forward to this
|
||||
* implementation or a subclass thereof.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
@Beta
|
||||
protected class StandardValues extends Maps.Values<K, V> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardValues() {
|
||||
super(ForwardingMap.this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #containsValue} in terms of the {@code
|
||||
* iterator} method of {@link #entrySet}. If you override {@link #entrySet}, you
|
||||
* may wish to override {@link #containsValue} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardContainsValue(@Nullable Object value) {
|
||||
return Maps.containsValueImpl(this, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link Map#entrySet} in terms of the following
|
||||
* methods: {@link ForwardingMap#clear}, {@link ForwardingMap#containsKey},
|
||||
* {@link ForwardingMap#get}, {@link ForwardingMap#isEmpty},
|
||||
* {@link ForwardingMap#remove}, and {@link ForwardingMap#size}. In many cases,
|
||||
* you may wish to override {@link #entrySet} to forward to this implementation
|
||||
* or a subclass thereof.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
@Beta
|
||||
protected abstract class StandardEntrySet extends Maps.EntrySet<K, V> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardEntrySet() {
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<K, V> map() {
|
||||
return ForwardingMap.this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #isEmpty} in terms of the {@code iterator}
|
||||
* method of {@link #entrySet}. If you override {@link #entrySet}, you may wish
|
||||
* to override {@link #isEmpty} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardIsEmpty() {
|
||||
return !entrySet().iterator().hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #equals} in terms of the {@code equals}
|
||||
* method of {@link #entrySet}. If you override {@link #entrySet}, you may wish
|
||||
* to override {@link #equals} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardEquals(@Nullable Object object) {
|
||||
return Maps.equalsImpl(this, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #hashCode} in terms of the {@code iterator}
|
||||
* method of {@link #entrySet}. If you override {@link #entrySet}, you may wish
|
||||
* to override {@link #hashCode} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected int standardHashCode() {
|
||||
return Sets.hashCodeImpl(entrySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toString} in terms of the {@code iterator}
|
||||
* method of {@link #entrySet}. If you override {@link #entrySet}, you may wish
|
||||
* to override {@link #toString} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected String standardToString() {
|
||||
return Maps.toStringImpl(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* A map entry which forwards all its method calls to another map entry.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing map entry as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <i>Warning:</i> The methods of {@code ForwardingMapEntry} forward
|
||||
* <i>indiscriminately</i> to the methods of the delegate. For example,
|
||||
* overriding {@link #getValue} alone <i>will not</i> change the behavior of
|
||||
* {@link #equals}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code equals} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardEquals} method.
|
||||
*
|
||||
* <p>
|
||||
* Each of the {@code standard} methods, where appropriate, use
|
||||
* {@link Objects#equal} to test equality for both keys and values. This may not
|
||||
* be the desired behavior for map implementations that use non-standard notions
|
||||
* of key equality, such as the entry of a {@code SortedMap} whose comparator is
|
||||
* not consistent with {@code equals}.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods are not guaranteed to be thread-safe, even when
|
||||
* all of the methods that they depend on are thread-safe.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingMapEntry<K, V> extends ForwardingObject implements Map.Entry<K, V> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingMapEntry() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Map.Entry<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return delegate().getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return delegate().getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
return delegate().setValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return delegate().equals(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #equals(Object)} in terms of
|
||||
* {@link #getKey()} and {@link #getValue()}. If you override either of these
|
||||
* methods, you may wish to override {@link #equals(Object)} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardEquals(@Nullable Object object) {
|
||||
if (object instanceof Entry) {
|
||||
Entry<?, ?> that = (Entry<?, ?>) object;
|
||||
return Objects.equal(this.getKey(), that.getKey()) && Objects.equal(this.getValue(), that.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #hashCode()} in terms of {@link #getKey()}
|
||||
* and {@link #getValue()}. If you override either of these methods, you may
|
||||
* wish to override {@link #hashCode()} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected int standardHashCode() {
|
||||
K k = getKey();
|
||||
V v = getValue();
|
||||
return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toString} in terms of {@link #getKey} and
|
||||
* {@link #getValue}. If you override either of these methods, you may wish to
|
||||
* override {@link #equals} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected String standardToString() {
|
||||
return getKey() + "=" + getValue();
|
||||
}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A multimap which forwards all its method calls to another multimap.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing multimap as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* @author Robert Konigsberg
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingMultimap<K, V> extends ForwardingObject implements Multimap<K, V> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingMultimap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Multimap<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public Map<K, Collection<V>> asMap() {
|
||||
return delegate().asMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
delegate().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
|
||||
return delegate().containsEntry(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(@Nullable Object key) {
|
||||
return delegate().containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@Nullable Object value) {
|
||||
return delegate().containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Entry<K, V>> entries() {
|
||||
return delegate().entries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> get(@Nullable K key) {
|
||||
return delegate().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multiset<K> keys() {
|
||||
return delegate().keys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return delegate().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean put(K key, V value) {
|
||||
return delegate().put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putAll(K key, Iterable<? extends V> values) {
|
||||
return delegate().putAll(key, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
|
||||
return delegate().putAll(multimap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(@Nullable Object key, @Nullable Object value) {
|
||||
return delegate().remove(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> removeAll(@Nullable Object key) {
|
||||
return delegate().removeAll(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> replaceValues(K key, Iterable<? extends V> values) {
|
||||
return delegate().replaceValues(key, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return delegate().values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return object == this || delegate().equals(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* A multiset which forwards all its method calls to another multiset.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing multiset as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> The methods of {@code ForwardingMultiset} forward
|
||||
* <b>indiscriminately</b> to the methods of the delegate. For example,
|
||||
* overriding {@link #add(Object, int)} alone <b>will not</b> change the
|
||||
* behavior of {@link #add(Object)}, which can lead to unexpected behavior. In
|
||||
* this case, you should override {@code add(Object)} as well, either providing
|
||||
* your own implementation, or delegating to the provided {@code standardAdd}
|
||||
* method.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods and any collection views they return are not
|
||||
* guaranteed to be thread-safe, even when all of the methods that they depend
|
||||
* on are thread-safe.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingMultiset<E> extends ForwardingCollection<E> implements Multiset<E> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingMultiset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Multiset<E> delegate();
|
||||
|
||||
@Override
|
||||
public int count(Object element) {
|
||||
return delegate().count(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int add(E element, int occurrences) {
|
||||
return delegate().add(element, occurrences);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remove(Object element, int occurrences) {
|
||||
return delegate().remove(element, occurrences);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<E> elementSet() {
|
||||
return delegate().elementSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<E>> entrySet() {
|
||||
return delegate().entrySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return object == this || delegate().equals(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setCount(E element, int count) {
|
||||
return delegate().setCount(element, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setCount(E element, int oldCount, int newCount) {
|
||||
return delegate().setCount(element, oldCount, newCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #contains} in terms of {@link #count}. If you
|
||||
* override {@link #count}, you may wish to override {@link #contains} to
|
||||
* forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Override
|
||||
protected boolean standardContains(@Nullable Object object) {
|
||||
return count(object) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #clear} in terms of the {@code iterator}
|
||||
* method of {@link #entrySet}. If you override {@link #entrySet}, you may wish
|
||||
* to override {@link #clear} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Override
|
||||
protected void standardClear() {
|
||||
Iterators.clear(entrySet().iterator());
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible, albeit inefficient, definition of {@link #count} in terms of
|
||||
* {@link #entrySet}. If you override {@link #entrySet}, you may wish to
|
||||
* override {@link #count} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected int standardCount(@Nullable Object object) {
|
||||
for (Entry<?> entry : this.entrySet()) {
|
||||
if (Objects.equal(entry.getElement(), object)) {
|
||||
return entry.getCount();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #add(Object)} in terms of
|
||||
* {@link #add(Object, int)}. If you override {@link #add(Object, int)}, you may
|
||||
* wish to override {@link #add(Object)} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardAdd(E element) {
|
||||
add(element, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #addAll(Collection)} in terms of
|
||||
* {@link #add(Object)} and {@link #add(Object, int)}. If you override either of
|
||||
* these methods, you may wish to override {@link #addAll(Collection)} to
|
||||
* forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
@Override
|
||||
protected boolean standardAddAll(Collection<? extends E> elementsToAdd) {
|
||||
return Multisets.addAllImpl(this, elementsToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #remove(Object)} in terms of
|
||||
* {@link #remove(Object, int)}. If you override {@link #remove(Object, int)},
|
||||
* you may wish to override {@link #remove(Object)} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Override
|
||||
protected boolean standardRemove(Object element) {
|
||||
return remove(element, 1) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #removeAll} in terms of the {@code
|
||||
* removeAll} method of {@link #elementSet}. If you override
|
||||
* {@link #elementSet}, you may wish to override {@link #removeAll} to forward
|
||||
* to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Override
|
||||
protected boolean standardRemoveAll(Collection<?> elementsToRemove) {
|
||||
return Multisets.removeAllImpl(this, elementsToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #retainAll} in terms of the {@code
|
||||
* retainAll} method of {@link #elementSet}. If you override
|
||||
* {@link #elementSet}, you may wish to override {@link #retainAll} to forward
|
||||
* to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Override
|
||||
protected boolean standardRetainAll(Collection<?> elementsToRetain) {
|
||||
return Multisets.retainAllImpl(this, elementsToRetain);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #setCount(Object, int)} in terms of
|
||||
* {@link #count(Object)}, {@link #add(Object, int)}, and
|
||||
* {@link #remove(Object, int)}. {@link #entrySet()}. If you override any of
|
||||
* these methods, you may wish to override {@link #setCount(Object, int)} to
|
||||
* forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected int standardSetCount(E element, int count) {
|
||||
return Multisets.setCountImpl(this, element, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #setCount(Object, int, int)} in terms of
|
||||
* {@link #count(Object)} and {@link #setCount(Object, int)}. If you override
|
||||
* either of these methods, you may wish to override
|
||||
* {@link #setCount(Object, int, int)} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardSetCount(E element, int oldCount, int newCount) {
|
||||
return Multisets.setCountImpl(this, element, oldCount, newCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link Multiset#elementSet} in terms of the
|
||||
* following methods: {@link ForwardingMultiset#clear},
|
||||
* {@link ForwardingMultiset#contains}, {@link ForwardingMultiset#containsAll},
|
||||
* {@link ForwardingMultiset#count}, {@link ForwardingMultiset#isEmpty}, the
|
||||
* {@link Set#size} and {@link Set#iterator} methods of
|
||||
* {@link ForwardingMultiset#entrySet}, and
|
||||
* {@link ForwardingMultiset#remove(Object, int)}. In many situations, you may
|
||||
* wish to override {@link ForwardingMultiset#elementSet} to forward to this
|
||||
* implementation or a subclass thereof.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
@Beta
|
||||
protected class StandardElementSet extends Multisets.ElementSet<E> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardElementSet() {
|
||||
}
|
||||
|
||||
@Override
|
||||
Multiset<E> multiset() {
|
||||
return ForwardingMultiset.this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #iterator} in terms of {@link #entrySet} and
|
||||
* {@link #remove(Object)}. If you override either of these methods, you may
|
||||
* wish to override {@link #iterator} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected Iterator<E> standardIterator() {
|
||||
return Multisets.iteratorImpl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible, albeit inefficient, definition of {@link #size} in terms of
|
||||
* {@link #entrySet}. If you override {@link #entrySet}, you may wish to
|
||||
* override {@link #size} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected int standardSize() {
|
||||
return Multisets.sizeImpl(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible, albeit inefficient, definition of {@link #size} in terms of
|
||||
* {@code entrySet().size()} and {@link #count}. If you override either of these
|
||||
* methods, you may wish to override {@link #size} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardEquals(@Nullable Object object) {
|
||||
return Multisets.equalsImpl(this, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #hashCode} as {@code entrySet().hashCode()} .
|
||||
* If you override {@link #entrySet}, you may wish to override {@link #hashCode}
|
||||
* to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected int standardHashCode() {
|
||||
return entrySet().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #toString} as {@code entrySet().toString()} .
|
||||
* If you override {@link #entrySet}, you may wish to override {@link #toString}
|
||||
* to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Override
|
||||
protected String standardToString() {
|
||||
return entrySet().toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.collect.CollectPreconditions.checkRemove;
|
||||
import static com.google.common.collect.Maps.keyOrNull;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.SortedMap;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* A navigable map which forwards all its method calls to another navigable map.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing map as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <i>Warning:</i> The methods of {@code ForwardingNavigableMap} forward
|
||||
* <i>indiscriminately</i> to the methods of the delegate. For example,
|
||||
* overriding {@link #put} alone <i>will not</i> change the behavior of
|
||||
* {@link #putAll}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code putAll} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardPutAll} method.
|
||||
*
|
||||
* <p>
|
||||
* Each of the {@code standard} methods uses the map's comparator (or the
|
||||
* natural ordering of the elements, if there is no comparator) to test element
|
||||
* equality. As a result, if the comparator is not consistent with equals, some
|
||||
* of the standard implementations may violate the {@code Map} contract.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods and the collection views they return are not
|
||||
* guaranteed to be thread-safe, even when all of the methods that they depend
|
||||
* on are thread-safe.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
* @since 12.0
|
||||
*/
|
||||
public abstract class ForwardingNavigableMap<K, V> extends ForwardingSortedMap<K, V> implements NavigableMap<K, V> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingNavigableMap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract NavigableMap<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public Entry<K, V> lowerEntry(K key) {
|
||||
return delegate().lowerEntry(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #lowerEntry} in terms of the
|
||||
* {@code lastEntry()} of {@link #headMap(Object, boolean)}. If you override
|
||||
* {@code headMap}, you may wish to override {@code lowerEntry} to forward to
|
||||
* this implementation.
|
||||
*/
|
||||
protected Entry<K, V> standardLowerEntry(K key) {
|
||||
return headMap(key, false).lastEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K lowerKey(K key) {
|
||||
return delegate().lowerKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #lowerKey} in terms of {@code lowerEntry}. If
|
||||
* you override {@link #lowerEntry}, you may wish to override {@code lowerKey}
|
||||
* to forward to this implementation.
|
||||
*/
|
||||
protected K standardLowerKey(K key) {
|
||||
return keyOrNull(lowerEntry(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> floorEntry(K key) {
|
||||
return delegate().floorEntry(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #floorEntry} in terms of the
|
||||
* {@code lastEntry()} of {@link #headMap(Object, boolean)}. If you override
|
||||
* {@code headMap}, you may wish to override {@code floorEntry} to forward to
|
||||
* this implementation.
|
||||
*/
|
||||
protected Entry<K, V> standardFloorEntry(K key) {
|
||||
return headMap(key, true).lastEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K floorKey(K key) {
|
||||
return delegate().floorKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #floorKey} in terms of {@code floorEntry}. If
|
||||
* you override {@code floorEntry}, you may wish to override {@code floorKey} to
|
||||
* forward to this implementation.
|
||||
*/
|
||||
protected K standardFloorKey(K key) {
|
||||
return keyOrNull(floorEntry(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> ceilingEntry(K key) {
|
||||
return delegate().ceilingEntry(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #ceilingEntry} in terms of the
|
||||
* {@code firstEntry()} of {@link #tailMap(Object, boolean)}. If you override
|
||||
* {@code tailMap}, you may wish to override {@code ceilingEntry} to forward to
|
||||
* this implementation.
|
||||
*/
|
||||
protected Entry<K, V> standardCeilingEntry(K key) {
|
||||
return tailMap(key, true).firstEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K ceilingKey(K key) {
|
||||
return delegate().ceilingKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #ceilingKey} in terms of
|
||||
* {@code ceilingEntry}. If you override {@code ceilingEntry}, you may wish to
|
||||
* override {@code ceilingKey} to forward to this implementation.
|
||||
*/
|
||||
protected K standardCeilingKey(K key) {
|
||||
return keyOrNull(ceilingEntry(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> higherEntry(K key) {
|
||||
return delegate().higherEntry(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #higherEntry} in terms of the
|
||||
* {@code firstEntry()} of {@link #tailMap(Object, boolean)}. If you override
|
||||
* {@code tailMap}, you may wish to override {@code higherEntry} to forward to
|
||||
* this implementation.
|
||||
*/
|
||||
protected Entry<K, V> standardHigherEntry(K key) {
|
||||
return tailMap(key, false).firstEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K higherKey(K key) {
|
||||
return delegate().higherKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #higherKey} in terms of {@code higherEntry}.
|
||||
* If you override {@code higherEntry}, you may wish to override
|
||||
* {@code higherKey} to forward to this implementation.
|
||||
*/
|
||||
protected K standardHigherKey(K key) {
|
||||
return keyOrNull(higherEntry(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> firstEntry() {
|
||||
return delegate().firstEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #firstEntry} in terms of the
|
||||
* {@code iterator()} of {@link #entrySet}. If you override {@code entrySet},
|
||||
* you may wish to override {@code firstEntry} to forward to this
|
||||
* implementation.
|
||||
*/
|
||||
protected Entry<K, V> standardFirstEntry() {
|
||||
return Iterables.getFirst(entrySet(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #firstKey} in terms of {@code firstEntry}. If
|
||||
* you override {@code firstEntry}, you may wish to override {@code firstKey} to
|
||||
* forward to this implementation.
|
||||
*/
|
||||
protected K standardFirstKey() {
|
||||
Entry<K, V> entry = firstEntry();
|
||||
if (entry == null) {
|
||||
throw new NoSuchElementException();
|
||||
} else {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> lastEntry() {
|
||||
return delegate().lastEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #lastEntry} in terms of the
|
||||
* {@code iterator()} of the {@link #entrySet} of {@link #descendingMap}. If you
|
||||
* override {@code descendingMap}, you may wish to override {@code lastEntry} to
|
||||
* forward to this implementation.
|
||||
*/
|
||||
protected Entry<K, V> standardLastEntry() {
|
||||
return Iterables.getFirst(descendingMap().entrySet(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #lastKey} in terms of {@code lastEntry}. If
|
||||
* you override {@code lastEntry}, you may wish to override {@code lastKey} to
|
||||
* forward to this implementation.
|
||||
*/
|
||||
protected K standardLastKey() {
|
||||
Entry<K, V> entry = lastEntry();
|
||||
if (entry == null) {
|
||||
throw new NoSuchElementException();
|
||||
} else {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> pollFirstEntry() {
|
||||
return delegate().pollFirstEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #pollFirstEntry} in terms of the
|
||||
* {@code iterator} of {@code entrySet}. If you override {@code entrySet}, you
|
||||
* may wish to override {@code pollFirstEntry} to forward to this
|
||||
* implementation.
|
||||
*/
|
||||
protected Entry<K, V> standardPollFirstEntry() {
|
||||
return Iterators.pollNext(entrySet().iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<K, V> pollLastEntry() {
|
||||
return delegate().pollLastEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #pollFirstEntry} in terms of the
|
||||
* {@code iterator} of the {@code entrySet} of {@code descendingMap}. If you
|
||||
* override {@code descendingMap}, you may wish to override
|
||||
* {@code pollFirstEntry} to forward to this implementation.
|
||||
*/
|
||||
protected Entry<K, V> standardPollLastEntry() {
|
||||
return Iterators.pollNext(descendingMap().entrySet().iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableMap<K, V> descendingMap() {
|
||||
return delegate().descendingMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link NavigableMap#descendingMap} in terms of
|
||||
* the methods of this {@code NavigableMap}. In many cases, you may wish to
|
||||
* override {@link ForwardingNavigableMap#descendingMap} to forward to this
|
||||
* implementation or a subclass thereof.
|
||||
*
|
||||
* <p>
|
||||
* In particular, this map iterates over entries with repeated calls to
|
||||
* {@link NavigableMap#lowerEntry}. If a more efficient means of iteration is
|
||||
* available, you may wish to override the {@code entryIterator()} method of
|
||||
* this class.
|
||||
*
|
||||
* @since 12.0
|
||||
*/
|
||||
@Beta
|
||||
protected class StandardDescendingMap extends Maps.DescendingMap<K, V> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardDescendingMap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
NavigableMap<K, V> forward() {
|
||||
return ForwardingNavigableMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterator<Entry<K, V>> entryIterator() {
|
||||
return new Iterator<Entry<K, V>>() {
|
||||
private Entry<K, V> toRemove = null;
|
||||
private Entry<K, V> nextOrNull = forward().lastEntry();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nextOrNull != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.util.Map.Entry<K, V> next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
try {
|
||||
return nextOrNull;
|
||||
} finally {
|
||||
toRemove = nextOrNull;
|
||||
nextOrNull = forward().lowerEntry(nextOrNull.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
checkRemove(toRemove != null);
|
||||
forward().remove(toRemove.getKey());
|
||||
toRemove = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<K> navigableKeySet() {
|
||||
return delegate().navigableKeySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link NavigableMap#navigableKeySet} in terms of
|
||||
* the methods of this {@code NavigableMap}. In many cases, you may wish to
|
||||
* override {@link ForwardingNavigableMap#navigableKeySet} to forward to this
|
||||
* implementation or a subclass thereof.
|
||||
*
|
||||
* @since 12.0
|
||||
*/
|
||||
@Beta
|
||||
protected class StandardNavigableKeySet extends Maps.NavigableKeySet<K, V> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardNavigableKeySet() {
|
||||
super(ForwardingNavigableMap.this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<K> descendingKeySet() {
|
||||
return delegate().descendingKeySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #descendingKeySet} as the
|
||||
* {@code navigableKeySet} of {@link #descendingMap}. (The
|
||||
* {@link StandardDescendingMap} implementation implements
|
||||
* {@code navigableKeySet} on its own, so as not to cause an infinite loop.) If
|
||||
* you override {@code descendingMap}, you may wish to override
|
||||
* {@code descendingKeySet} to forward to this implementation.
|
||||
*/
|
||||
@Beta
|
||||
protected NavigableSet<K> standardDescendingKeySet() {
|
||||
return descendingMap().navigableKeySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #subMap(Object, Object)} in terms of
|
||||
* {@link #subMap(Object, boolean, Object, boolean)}. If you override
|
||||
* {@code subMap(K, boolean, K, boolean)}, you may wish to override
|
||||
* {@code subMap} to forward to this implementation.
|
||||
*/
|
||||
@Override
|
||||
protected SortedMap<K, V> standardSubMap(K fromKey, K toKey) {
|
||||
return subMap(fromKey, true, toKey, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
|
||||
return delegate().subMap(fromKey, fromInclusive, toKey, toInclusive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
|
||||
return delegate().headMap(toKey, inclusive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
|
||||
return delegate().tailMap(fromKey, inclusive);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #headMap(Object)} in terms of
|
||||
* {@link #headMap(Object, boolean)}. If you override
|
||||
* {@code headMap(K, boolean)}, you may wish to override {@code headMap} to
|
||||
* forward to this implementation.
|
||||
*/
|
||||
protected SortedMap<K, V> standardHeadMap(K toKey) {
|
||||
return headMap(toKey, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #tailMap(Object)} in terms of
|
||||
* {@link #tailMap(Object, boolean)}. If you override
|
||||
* {@code tailMap(K, boolean)}, you may wish to override {@code tailMap} to
|
||||
* forward to this implementation.
|
||||
*/
|
||||
protected SortedMap<K, V> standardTailMap(K fromKey) {
|
||||
return tailMap(fromKey, true);
|
||||
}
|
||||
}
|
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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 com.google.common.collect;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
|
||||
/**
|
||||
* A navigable set which forwards all its method calls to another navigable set.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing set as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <i>Warning:</i> The methods of {@code ForwardingNavigableSet} forward
|
||||
* <i>indiscriminately</i> to the methods of the delegate. For example,
|
||||
* overriding {@link #add} alone <i>will not</i> change the behavior of
|
||||
* {@link #addAll}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code addAll} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardAddAll} method.
|
||||
*
|
||||
* <p>
|
||||
* Each of the {@code standard} methods uses the set's comparator (or the
|
||||
* natural ordering of the elements, if there is no comparator) to test element
|
||||
* equality. As a result, if the comparator is not consistent with equals, some
|
||||
* of the standard implementations may violate the {@code Set} contract.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods and the collection views they return are not
|
||||
* guaranteed to be thread-safe, even when all of the methods that they depend
|
||||
* on are thread-safe.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
* @since 12.0
|
||||
*/
|
||||
public abstract class ForwardingNavigableSet<E> extends ForwardingSortedSet<E> implements NavigableSet<E> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingNavigableSet() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract NavigableSet<E> delegate();
|
||||
|
||||
@Override
|
||||
public E lower(E e) {
|
||||
return delegate().lower(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #lower} in terms of the
|
||||
* {@code descendingIterator} method of {@link #headSet(Object, boolean)}. If
|
||||
* you override {@link #headSet(Object, boolean)}, you may wish to override
|
||||
* {@link #lower} to forward to this implementation.
|
||||
*/
|
||||
protected E standardLower(E e) {
|
||||
return Iterators.getNext(headSet(e, false).descendingIterator(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E floor(E e) {
|
||||
return delegate().floor(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #floor} in terms of the
|
||||
* {@code descendingIterator} method of {@link #headSet(Object, boolean)}. If
|
||||
* you override {@link #headSet(Object, boolean)}, you may wish to override
|
||||
* {@link #floor} to forward to this implementation.
|
||||
*/
|
||||
protected E standardFloor(E e) {
|
||||
return Iterators.getNext(headSet(e, true).descendingIterator(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E ceiling(E e) {
|
||||
return delegate().ceiling(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #ceiling} in terms of the {@code iterator}
|
||||
* method of {@link #tailSet(Object, boolean)}. If you override
|
||||
* {@link #tailSet(Object, boolean)}, you may wish to override {@link #ceiling}
|
||||
* to forward to this implementation.
|
||||
*/
|
||||
protected E standardCeiling(E e) {
|
||||
return Iterators.getNext(tailSet(e, true).iterator(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E higher(E e) {
|
||||
return delegate().higher(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #higher} in terms of the {@code iterator}
|
||||
* method of {@link #tailSet(Object, boolean)}. If you override
|
||||
* {@link #tailSet(Object, boolean)}, you may wish to override {@link #higher}
|
||||
* to forward to this implementation.
|
||||
*/
|
||||
protected E standardHigher(E e) {
|
||||
return Iterators.getNext(tailSet(e, false).iterator(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pollFirst() {
|
||||
return delegate().pollFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #pollFirst} in terms of the {@code iterator}
|
||||
* method. If you override {@link #iterator} you may wish to override
|
||||
* {@link #pollFirst} to forward to this implementation.
|
||||
*/
|
||||
protected E standardPollFirst() {
|
||||
return Iterators.pollNext(iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public E pollLast() {
|
||||
return delegate().pollLast();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #pollLast} in terms of the
|
||||
* {@code descendingIterator} method. If you override
|
||||
* {@link #descendingIterator} you may wish to override {@link #pollLast} to
|
||||
* forward to this implementation.
|
||||
*/
|
||||
protected E standardPollLast() {
|
||||
return Iterators.pollNext(descendingIterator());
|
||||
}
|
||||
|
||||
protected E standardFirst() {
|
||||
return iterator().next();
|
||||
}
|
||||
|
||||
protected E standardLast() {
|
||||
return descendingIterator().next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<E> descendingSet() {
|
||||
return delegate().descendingSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link NavigableSet#descendingSet} in terms of
|
||||
* the other methods of {@link NavigableSet}, notably including
|
||||
* {@link NavigableSet#descendingIterator}.
|
||||
*
|
||||
* <p>
|
||||
* In many cases, you may wish to override
|
||||
* {@link ForwardingNavigableSet#descendingSet} to forward to this
|
||||
* implementation or a subclass thereof.
|
||||
*
|
||||
* @since 12.0
|
||||
*/
|
||||
@Beta
|
||||
protected class StandardDescendingSet extends Sets.DescendingSet<E> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardDescendingSet() {
|
||||
super(ForwardingNavigableSet.this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> descendingIterator() {
|
||||
return delegate().descendingIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
|
||||
return delegate().subSet(fromElement, fromInclusive, toElement, toInclusive);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #subSet(Object, boolean, Object, boolean)} in
|
||||
* terms of the {@code headSet} and {@code tailSet} methods. In many cases, you
|
||||
* may wish to override {@link #subSet(Object, boolean, Object, boolean)} to
|
||||
* forward to this implementation.
|
||||
*/
|
||||
@Beta
|
||||
protected NavigableSet<E> standardSubSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
|
||||
return tailSet(fromElement, fromInclusive).headSet(toElement, toInclusive);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #subSet(Object, Object)} in terms of the
|
||||
* {@link #subSet(Object, boolean, Object, boolean)} method. If you override
|
||||
* {@link #subSet(Object, boolean, Object, boolean)}, you may wish to override
|
||||
* {@link #subSet(Object, Object)} to forward to this implementation.
|
||||
*/
|
||||
@Override
|
||||
protected SortedSet<E> standardSubSet(E fromElement, E toElement) {
|
||||
return subSet(fromElement, true, toElement, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<E> headSet(E toElement, boolean inclusive) {
|
||||
return delegate().headSet(toElement, inclusive);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #headSet(Object)} in terms of the
|
||||
* {@link #headSet(Object, boolean)} method. If you override
|
||||
* {@link #headSet(Object, boolean)}, you may wish to override
|
||||
* {@link #headSet(Object)} to forward to this implementation.
|
||||
*/
|
||||
protected SortedSet<E> standardHeadSet(E toElement) {
|
||||
return headSet(toElement, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
|
||||
return delegate().tailSet(fromElement, inclusive);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #tailSet(Object)} in terms of the
|
||||
* {@link #tailSet(Object, boolean)} method. If you override
|
||||
* {@link #tailSet(Object, boolean)}, you may wish to override
|
||||
* {@link #tailSet(Object)} to forward to this implementation.
|
||||
*/
|
||||
protected SortedSet<E> standardTailSet(E fromElement) {
|
||||
return tailSet(fromElement, true);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* An abstract base class for implementing the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>. The {@link #delegate()} method must be overridden to return the
|
||||
* instance being decorated.
|
||||
*
|
||||
* <p>
|
||||
* This class does <i>not</i> forward the {@code hashCode} and {@code equals}
|
||||
* methods through to the backing object, but relies on {@code Object}'s
|
||||
* implementation. This is necessary to preserve the symmetry of {@code equals}.
|
||||
* Custom definitions of equality are usually based on an interface, such as
|
||||
* {@code Set} or {@code List}, so that the implementation of {@code equals} can
|
||||
* cast the object being tested for equality to the custom interface. {@code
|
||||
* ForwardingObject} implements no such custom interfaces directly; they are
|
||||
* implemented only in subclasses. Therefore, forwarding {@code equals} would
|
||||
* break symmetry, as the forwarding object might consider itself equal to the
|
||||
* object being tested, but the reverse could not be true. This behavior is
|
||||
* consistent with the JDK's collection wrappers, such as
|
||||
* {@link java.util.Collections#unmodifiableCollection}. Use an
|
||||
* interface-specific subclass of {@code ForwardingObject}, such as
|
||||
* {@link ForwardingList}, to preserve equality behavior, or override
|
||||
* {@code equals} directly.
|
||||
*
|
||||
* <p>
|
||||
* The {@code toString} method is forwarded to the delegate. Although this class
|
||||
* does not implement {@link Serializable}, a serializable subclass may be
|
||||
* created since this class has a parameter-less constructor.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingObject {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingObject() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the backing delegate instance that methods are forwarded to. Abstract
|
||||
* subclasses generally override this method with an abstract method that has a
|
||||
* more specific return type, such as {@link ForwardingSet#delegate}. Concrete
|
||||
* subclasses override this method to supply the instance being decorated.
|
||||
*/
|
||||
protected abstract Object delegate();
|
||||
|
||||
/**
|
||||
* Returns the string representation generated by the delegate's
|
||||
* {@code toString} method.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate().toString();
|
||||
}
|
||||
|
||||
/* No equals or hashCode. See class comments for details. */
|
||||
}
|
126
sources/main/java/com/google/common/collect/ForwardingQueue.java
Normal file
126
sources/main/java/com/google/common/collect/ForwardingQueue.java
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A queue which forwards all its method calls to another queue. Subclasses
|
||||
* should override one or more methods to modify the behavior of the backing
|
||||
* queue as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> The methods of {@code ForwardingQueue} forward
|
||||
* <b>indiscriminately</b> to the methods of the delegate. For example,
|
||||
* overriding {@link #add} alone <b>will not</b> change the behavior of
|
||||
* {@link #offer} which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code offer} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardOffer} method.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods are not guaranteed to be thread-safe, even when
|
||||
* all of the methods that they depend on are thread-safe.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingQueue<E> extends ForwardingCollection<E> implements Queue<E> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingQueue() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Queue<E> delegate();
|
||||
|
||||
@Override
|
||||
public boolean offer(E o) {
|
||||
return delegate().offer(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E poll() {
|
||||
return delegate().poll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove() {
|
||||
return delegate().remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peek() {
|
||||
return delegate().peek();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E element() {
|
||||
return delegate().element();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #offer} in terms of {@link #add}. If you
|
||||
* override {@link #add}, you may wish to override {@link #offer} to forward to
|
||||
* this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardOffer(E e) {
|
||||
try {
|
||||
return add(e);
|
||||
} catch (IllegalStateException caught) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #peek} in terms of {@link #element}. If you
|
||||
* override {@link #element}, you may wish to override {@link #peek} to forward
|
||||
* to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected E standardPeek() {
|
||||
try {
|
||||
return element();
|
||||
} catch (NoSuchElementException caught) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #poll} in terms of {@link #remove}. If you
|
||||
* override {@link #remove}, you may wish to override {@link #poll} to forward
|
||||
* to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected E standardPoll() {
|
||||
try {
|
||||
return remove();
|
||||
} catch (NoSuchElementException caught) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
106
sources/main/java/com/google/common/collect/ForwardingSet.java
Normal file
106
sources/main/java/com/google/common/collect/ForwardingSet.java
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A set which forwards all its method calls to another set. Subclasses should
|
||||
* override one or more methods to modify the behavior of the backing set as
|
||||
* desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> The methods of {@code ForwardingSet} forward
|
||||
* <b>indiscriminately</b> to the methods of the delegate. For example,
|
||||
* overriding {@link #add} alone <b>will not</b> change the behavior of
|
||||
* {@link #addAll}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code addAll} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardAddAll} method.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods are not guaranteed to be thread-safe, even when
|
||||
* all of the methods that they depend on are thread-safe.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingSet<E> extends ForwardingCollection<E> implements Set<E> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingSet() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Set<E> delegate();
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object object) {
|
||||
return object == this || delegate().equals(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #removeAll} in terms of {@link #iterator} and
|
||||
* {@link #remove}. If you override {@code iterator} or {@code remove}, you may
|
||||
* wish to override {@link #removeAll} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0 (this version overrides the {@code ForwardingCollection} version
|
||||
* as of 12.0)
|
||||
*/
|
||||
@Override
|
||||
protected boolean standardRemoveAll(Collection<?> collection) {
|
||||
return Sets.removeAllImpl(this, checkNotNull(collection)); // for GWT
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #equals} in terms of {@link #size} and
|
||||
* {@link #containsAll}. If you override either of those methods, you may wish
|
||||
* to override {@link #equals} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected boolean standardEquals(@Nullable Object object) {
|
||||
return Sets.equalsImpl(this, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #hashCode} in terms of {@link #iterator}. If
|
||||
* you override {@link #iterator}, you may wish to override {@link #equals} to
|
||||
* forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
protected int standardHashCode() {
|
||||
return Sets.hashCodeImpl(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 com.google.common.collect;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A set multimap which forwards all its method calls to another set multimap.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing multimap as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* @author Kurt Alfred Kluever
|
||||
* @since 3.0
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingSetMultimap<K, V> extends ForwardingMultimap<K, V> implements SetMultimap<K, V> {
|
||||
|
||||
@Override
|
||||
protected abstract SetMultimap<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entries() {
|
||||
return delegate().entries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> get(@Nullable K key) {
|
||||
return delegate().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> removeAll(@Nullable Object key) {
|
||||
return delegate().removeAll(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> replaceValues(K key, Iterable<? extends V> values) {
|
||||
return delegate().replaceValues(key, values);
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.SortedMap;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A sorted map which forwards all its method calls to another sorted map.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing sorted map as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <i>Warning:</i> The methods of {@code ForwardingSortedMap} forward
|
||||
* <i>indiscriminately</i> to the methods of the delegate. For example,
|
||||
* overriding {@link #put} alone <i>will not</i> change the behavior of
|
||||
* {@link #putAll}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code putAll} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardPutAll} method.
|
||||
*
|
||||
* <p>
|
||||
* Each of the {@code standard} methods, where appropriate, use the comparator
|
||||
* of the map to test equality for both keys and values, unlike
|
||||
* {@code ForwardingMap}.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods and the collection views they return are not
|
||||
* guaranteed to be thread-safe, even when all of the methods that they depend
|
||||
* on are thread-safe.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingSortedMap<K, V> extends ForwardingMap<K, V> implements SortedMap<K, V> {
|
||||
// TODO(user): identify places where thread safety is actually lost
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingSortedMap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract SortedMap<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public Comparator<? super K> comparator() {
|
||||
return delegate().comparator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K firstKey() {
|
||||
return delegate().firstKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<K, V> headMap(K toKey) {
|
||||
return delegate().headMap(toKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K lastKey() {
|
||||
return delegate().lastKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<K, V> subMap(K fromKey, K toKey) {
|
||||
return delegate().subMap(fromKey, toKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<K, V> tailMap(K fromKey) {
|
||||
return delegate().tailMap(fromKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link SortedMap#keySet} in terms of the methods
|
||||
* of {@code ForwardingSortedMap}. In many cases, you may wish to override
|
||||
* {@link ForwardingSortedMap#keySet} to forward to this implementation or a
|
||||
* subclass thereof.
|
||||
*
|
||||
* @since 15.0
|
||||
*/
|
||||
@Beta
|
||||
protected class StandardKeySet extends Maps.SortedKeySet<K, V> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardKeySet() {
|
||||
super(ForwardingSortedMap.this);
|
||||
}
|
||||
}
|
||||
|
||||
// unsafe, but worst case is a CCE is thrown, which callers will be expecting
|
||||
@SuppressWarnings("unchecked")
|
||||
private int unsafeCompare(Object k1, Object k2) {
|
||||
Comparator<? super K> comparator = comparator();
|
||||
if (comparator == null) {
|
||||
return ((Comparable<Object>) k1).compareTo(k2);
|
||||
} else {
|
||||
return ((Comparator<Object>) comparator).compare(k1, k2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #containsKey} in terms of the {@code
|
||||
* firstKey()} method of {@link #tailMap}. If you override {@link #tailMap}, you
|
||||
* may wish to override {@link #containsKey} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Override
|
||||
@Beta
|
||||
protected boolean standardContainsKey(@Nullable Object key) {
|
||||
try {
|
||||
// any CCE will be caught
|
||||
@SuppressWarnings("unchecked")
|
||||
SortedMap<Object, V> self = (SortedMap<Object, V>) this;
|
||||
Object ceilingKey = self.tailMap(key).firstKey();
|
||||
return unsafeCompare(ceilingKey, key) == 0;
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
} catch (NoSuchElementException e) {
|
||||
return false;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #subMap(Object, Object)} in terms
|
||||
* of {@link #headMap(Object)} and {@link #tailMap(Object)}. In some situations,
|
||||
* you may wish to override {@link #subMap(Object, Object)} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected SortedMap<K, V> standardSubMap(K fromKey, K toKey) {
|
||||
checkArgument(unsafeCompare(fromKey, toKey) <= 0, "fromKey must be <= toKey");
|
||||
return tailMap(fromKey).headMap(toKey);
|
||||
}
|
||||
}
|
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.NavigableSet;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A sorted multiset which forwards all its method calls to another sorted
|
||||
* multiset. Subclasses should override one or more methods to modify the
|
||||
* behavior of the backing multiset as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> The methods of {@code ForwardingSortedMultiset} forward
|
||||
* <b>indiscriminately</b> to the methods of the delegate. For example,
|
||||
* overriding {@link #add(Object, int)} alone <b>will not</b> change the
|
||||
* behavior of {@link #add(Object)}, which can lead to unexpected behavior. In
|
||||
* this case, you should override {@code add(Object)} as well, either providing
|
||||
* your own implementation, or delegating to the provided {@code
|
||||
* standardAdd} method.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods and any collection views they return are not
|
||||
* guaranteed to be thread-safe, even when all of the methods that they depend
|
||||
* on are thread-safe.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
* @since 15.0
|
||||
*/
|
||||
@Beta
|
||||
@GwtCompatible(emulated = true)
|
||||
public abstract class ForwardingSortedMultiset<E> extends ForwardingMultiset<E> implements SortedMultiset<E> {
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingSortedMultiset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract SortedMultiset<E> delegate();
|
||||
|
||||
@Override
|
||||
public NavigableSet<E> elementSet() {
|
||||
return (NavigableSet<E>) super.elementSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible implementation of {@link SortedMultiset#elementSet} in terms of
|
||||
* the following methods: {@link SortedMultiset#clear},
|
||||
* {@link SortedMultiset#comparator}, {@link SortedMultiset#contains},
|
||||
* {@link SortedMultiset#containsAll}, {@link SortedMultiset#count},
|
||||
* {@link SortedMultiset#firstEntry} {@link SortedMultiset#headMultiset},
|
||||
* {@link SortedMultiset#isEmpty}, {@link SortedMultiset#lastEntry},
|
||||
* {@link SortedMultiset#subMultiset}, {@link SortedMultiset#tailMultiset}, the
|
||||
* {@code size()} and {@code iterator()} methods of
|
||||
* {@link SortedMultiset#entrySet}, and
|
||||
* {@link SortedMultiset#remove(Object, int)}. In many situations, you may wish
|
||||
* to override {@link SortedMultiset#elementSet} to forward to this
|
||||
* implementation or a subclass thereof.
|
||||
*/
|
||||
protected class StandardElementSet extends SortedMultisets.NavigableElementSet<E> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardElementSet() {
|
||||
super(ForwardingSortedMultiset.this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<? super E> comparator() {
|
||||
return delegate().comparator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> descendingMultiset() {
|
||||
return delegate().descendingMultiset();
|
||||
}
|
||||
|
||||
/**
|
||||
* A skeleton implementation of a descending multiset view. Normally,
|
||||
* {@link #descendingMultiset()} will not reflect any changes you make to the
|
||||
* behavior of methods such as {@link #add(Object)} or {@link #pollFirstEntry}.
|
||||
* This skeleton implementation correctly delegates each of its operations to
|
||||
* the appropriate methods of this {@code
|
||||
* ForwardingSortedMultiset}.
|
||||
*
|
||||
* In many cases, you may wish to override {@link #descendingMultiset()} to
|
||||
* return an instance of a subclass of {@code StandardDescendingMultiset}.
|
||||
*/
|
||||
protected abstract class StandardDescendingMultiset extends DescendingMultiset<E> {
|
||||
/** Constructor for use by subclasses. */
|
||||
public StandardDescendingMultiset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
SortedMultiset<E> forwardMultiset() {
|
||||
return ForwardingSortedMultiset.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> firstEntry() {
|
||||
return delegate().firstEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #firstEntry()} in terms of
|
||||
* {@code entrySet().iterator()}.
|
||||
*
|
||||
* If you override {@link #entrySet()}, you may wish to override
|
||||
* {@link #firstEntry()} to forward to this implementation.
|
||||
*/
|
||||
protected Entry<E> standardFirstEntry() {
|
||||
Iterator<Entry<E>> entryIterator = entrySet().iterator();
|
||||
if (!entryIterator.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
Entry<E> entry = entryIterator.next();
|
||||
return Multisets.immutableEntry(entry.getElement(), entry.getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> lastEntry() {
|
||||
return delegate().lastEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #lastEntry()} in terms of {@code
|
||||
* descendingMultiset().entrySet().iterator()}.
|
||||
*
|
||||
* If you override {@link #descendingMultiset} or {@link #entrySet()}, you may
|
||||
* wish to override {@link #firstEntry()} to forward to this implementation.
|
||||
*/
|
||||
protected Entry<E> standardLastEntry() {
|
||||
Iterator<Entry<E>> entryIterator = descendingMultiset().entrySet().iterator();
|
||||
if (!entryIterator.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
Entry<E> entry = entryIterator.next();
|
||||
return Multisets.immutableEntry(entry.getElement(), entry.getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> pollFirstEntry() {
|
||||
return delegate().pollFirstEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #pollFirstEntry()} in terms of
|
||||
* {@code entrySet().iterator()}.
|
||||
*
|
||||
* If you override {@link #entrySet()}, you may wish to override
|
||||
* {@link #pollFirstEntry()} to forward to this implementation.
|
||||
*/
|
||||
protected Entry<E> standardPollFirstEntry() {
|
||||
Iterator<Entry<E>> entryIterator = entrySet().iterator();
|
||||
if (!entryIterator.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
Entry<E> entry = entryIterator.next();
|
||||
entry = Multisets.immutableEntry(entry.getElement(), entry.getCount());
|
||||
entryIterator.remove();
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<E> pollLastEntry() {
|
||||
return delegate().pollLastEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #pollLastEntry()} in terms of {@code
|
||||
* descendingMultiset().entrySet().iterator()}.
|
||||
*
|
||||
* If you override {@link #descendingMultiset()} or {@link #entrySet()}, you may
|
||||
* wish to override {@link #pollLastEntry()} to forward to this implementation.
|
||||
*/
|
||||
protected Entry<E> standardPollLastEntry() {
|
||||
Iterator<Entry<E>> entryIterator = descendingMultiset().entrySet().iterator();
|
||||
if (!entryIterator.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
Entry<E> entry = entryIterator.next();
|
||||
entry = Multisets.immutableEntry(entry.getElement(), entry.getCount());
|
||||
entryIterator.remove();
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
|
||||
return delegate().headMultiset(upperBound, boundType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> subMultiset(E lowerBound, BoundType lowerBoundType, E upperBound,
|
||||
BoundType upperBoundType) {
|
||||
return delegate().subMultiset(lowerBound, lowerBoundType, upperBound, upperBoundType);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of
|
||||
* {@link #subMultiset(Object, BoundType, Object, BoundType)} in terms of
|
||||
* {@link #headMultiset(Object, BoundType) headMultiset} and
|
||||
* {@link #tailMultiset(Object, BoundType) tailMultiset}.
|
||||
*
|
||||
* If you override either of these methods, you may wish to override
|
||||
* {@link #subMultiset(Object, BoundType, Object, BoundType)} to forward to this
|
||||
* implementation.
|
||||
*/
|
||||
protected SortedMultiset<E> standardSubMultiset(E lowerBound, BoundType lowerBoundType, E upperBound,
|
||||
BoundType upperBoundType) {
|
||||
return tailMultiset(lowerBound, lowerBoundType).headMultiset(upperBound, upperBoundType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
|
||||
return delegate().tailMultiset(lowerBound, boundType);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A sorted set which forwards all its method calls to another sorted set.
|
||||
* Subclasses should override one or more methods to modify the behavior of the
|
||||
* backing sorted set as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* <p>
|
||||
* <i>Warning:</i> The methods of {@code ForwardingSortedSet} forward
|
||||
* <i>indiscriminately</i> to the methods of the delegate. For example,
|
||||
* overriding {@link #add} alone <i>will not</i> change the behavior of
|
||||
* {@link #addAll}, which can lead to unexpected behavior. In this case, you
|
||||
* should override {@code addAll} as well, either providing your own
|
||||
* implementation, or delegating to the provided {@code standardAddAll} method.
|
||||
*
|
||||
* <p>
|
||||
* Each of the {@code standard} methods, where appropriate, uses the set's
|
||||
* comparator (or the natural ordering of the elements, if there is no
|
||||
* comparator) to test element equality. As a result, if the comparator is not
|
||||
* consistent with equals, some of the standard implementations may violate the
|
||||
* {@code Set} contract.
|
||||
*
|
||||
* <p>
|
||||
* The {@code standard} methods and the collection views they return are not
|
||||
* guaranteed to be thread-safe, even when all of the methods that they depend
|
||||
* on are thread-safe.
|
||||
*
|
||||
* @author Mike Bostock
|
||||
* @author Louis Wasserman
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingSortedSet<E> extends ForwardingSet<E> implements SortedSet<E> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingSortedSet() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract SortedSet<E> delegate();
|
||||
|
||||
@Override
|
||||
public Comparator<? super E> comparator() {
|
||||
return delegate().comparator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E first() {
|
||||
return delegate().first();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> headSet(E toElement) {
|
||||
return delegate().headSet(toElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E last() {
|
||||
return delegate().last();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> subSet(E fromElement, E toElement) {
|
||||
return delegate().subSet(fromElement, toElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<E> tailSet(E fromElement) {
|
||||
return delegate().tailSet(fromElement);
|
||||
}
|
||||
|
||||
// unsafe, but worst case is a CCE is thrown, which callers will be expecting
|
||||
@SuppressWarnings("unchecked")
|
||||
private int unsafeCompare(Object o1, Object o2) {
|
||||
Comparator<? super E> comparator = comparator();
|
||||
return (comparator == null) ? ((Comparable<Object>) o1).compareTo(o2)
|
||||
: ((Comparator<Object>) comparator).compare(o1, o2);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #contains} in terms of the {@code first()}
|
||||
* method of {@link #tailSet}. If you override {@link #tailSet}, you may wish to
|
||||
* override {@link #contains} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Override
|
||||
@Beta
|
||||
protected boolean standardContains(@Nullable Object object) {
|
||||
try {
|
||||
// any ClassCastExceptions are caught
|
||||
@SuppressWarnings("unchecked")
|
||||
SortedSet<Object> self = (SortedSet<Object>) this;
|
||||
Object ceiling = self.tailSet(object).first();
|
||||
return unsafeCompare(ceiling, object) == 0;
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
} catch (NoSuchElementException e) {
|
||||
return false;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible definition of {@link #remove} in terms of the {@code iterator()}
|
||||
* method of {@link #tailSet}. If you override {@link #tailSet}, you may wish to
|
||||
* override {@link #remove} to forward to this implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Override
|
||||
@Beta
|
||||
protected boolean standardRemove(@Nullable Object object) {
|
||||
try {
|
||||
// any ClassCastExceptions are caught
|
||||
@SuppressWarnings("unchecked")
|
||||
SortedSet<Object> self = (SortedSet<Object>) this;
|
||||
Iterator<Object> iterator = self.tailSet(object).iterator();
|
||||
if (iterator.hasNext()) {
|
||||
Object ceiling = iterator.next();
|
||||
if (unsafeCompare(ceiling, object) == 0) {
|
||||
iterator.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A sensible default implementation of {@link #subSet(Object, Object)} in terms
|
||||
* of {@link #headSet(Object)} and {@link #tailSet(Object)}. In some situations,
|
||||
* you may wish to override {@link #subSet(Object, Object)} to forward to this
|
||||
* implementation.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
@Beta
|
||||
protected SortedSet<E> standardSubSet(E fromElement, E toElement) {
|
||||
return tailSet(fromElement).headSet(toElement);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 com.google.common.collect;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A sorted set multimap which forwards all its method calls to another sorted
|
||||
* set multimap. Subclasses should override one or more methods to modify the
|
||||
* behavior of the backing multimap as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* @author Kurt Alfred Kluever
|
||||
* @since 3.0
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingSortedSetMultimap<K, V> extends ForwardingSetMultimap<K, V>
|
||||
implements SortedSetMultimap<K, V> {
|
||||
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingSortedSetMultimap() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract SortedSetMultimap<K, V> delegate();
|
||||
|
||||
@Override
|
||||
public SortedSet<V> get(@Nullable K key) {
|
||||
return delegate().get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<V> removeAll(@Nullable Object key) {
|
||||
return delegate().removeAll(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<V> replaceValues(K key, Iterable<? extends V> values) {
|
||||
return delegate().replaceValues(key, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<? super V> valueComparator() {
|
||||
return delegate().valueComparator();
|
||||
}
|
||||
}
|
148
sources/main/java/com/google/common/collect/ForwardingTable.java
Normal file
148
sources/main/java/com/google/common/collect/ForwardingTable.java
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* A table which forwards all its method calls to another table. Subclasses
|
||||
* should override one or more methods to modify the behavior of the backing map
|
||||
* as desired per the
|
||||
* <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator
|
||||
* pattern</a>.
|
||||
*
|
||||
* @author Gregory Kick
|
||||
* @since 7.0
|
||||
*/
|
||||
@GwtCompatible
|
||||
public abstract class ForwardingTable<R, C, V> extends ForwardingObject implements Table<R, C, V> {
|
||||
/** Constructor for use by subclasses. */
|
||||
protected ForwardingTable() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract Table<R, C, V> delegate();
|
||||
|
||||
@Override
|
||||
public Set<Cell<R, C, V>> cellSet() {
|
||||
return delegate().cellSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
delegate().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<R, V> column(C columnKey) {
|
||||
return delegate().column(columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<C> columnKeySet() {
|
||||
return delegate().columnKeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<C, Map<R, V>> columnMap() {
|
||||
return delegate().columnMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object rowKey, Object columnKey) {
|
||||
return delegate().contains(rowKey, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsColumn(Object columnKey) {
|
||||
return delegate().containsColumn(columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsRow(Object rowKey) {
|
||||
return delegate().containsRow(rowKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return delegate().containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object rowKey, Object columnKey) {
|
||||
return delegate().get(rowKey, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegate().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(R rowKey, C columnKey, V value) {
|
||||
return delegate().put(rowKey, columnKey, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
|
||||
delegate().putAll(table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object rowKey, Object columnKey) {
|
||||
return delegate().remove(rowKey, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<C, V> row(R rowKey) {
|
||||
return delegate().row(rowKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<R> rowKeySet() {
|
||||
return delegate().rowKeySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<R, Map<C, V>> rowMap() {
|
||||
return delegate().rowMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegate().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return delegate().values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj == this) || delegate().equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate().hashCode();
|
||||
}
|
||||
}
|
275
sources/main/java/com/google/common/collect/GeneralRange.java
Normal file
275
sources/main/java/com/google/common/collect/GeneralRange.java
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.BoundType.CLOSED;
|
||||
import static com.google.common.collect.BoundType.OPEN;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* A generalized interval on any ordering, for internal use. Supports
|
||||
* {@code null}. Unlike {@link Range}, this allows the use of an arbitrary
|
||||
* comparator. This is designed for use in the implementation of subcollections
|
||||
* of sorted collection types.
|
||||
*
|
||||
* <p>
|
||||
* Whenever possible, use {@code Range} instead, which is better supported.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible(serializable = true)
|
||||
final class GeneralRange<T> implements Serializable {
|
||||
/**
|
||||
* Converts a Range to a GeneralRange.
|
||||
*/
|
||||
static <T extends Comparable> GeneralRange<T> from(Range<T> range) {
|
||||
@Nullable
|
||||
T lowerEndpoint = range.hasLowerBound() ? range.lowerEndpoint() : null;
|
||||
BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : OPEN;
|
||||
|
||||
@Nullable
|
||||
T upperEndpoint = range.hasUpperBound() ? range.upperEndpoint() : null;
|
||||
BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : OPEN;
|
||||
return new GeneralRange<T>(Ordering.natural(), range.hasLowerBound(), lowerEndpoint, lowerBoundType,
|
||||
range.hasUpperBound(), upperEndpoint, upperBoundType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the whole range relative to the specified comparator.
|
||||
*/
|
||||
static <T> GeneralRange<T> all(Comparator<? super T> comparator) {
|
||||
return new GeneralRange<T>(comparator, false, null, OPEN, false, null, OPEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns everything above the endpoint relative to the specified comparator,
|
||||
* with the specified endpoint behavior.
|
||||
*/
|
||||
static <T> GeneralRange<T> downTo(Comparator<? super T> comparator, @Nullable T endpoint, BoundType boundType) {
|
||||
return new GeneralRange<T>(comparator, true, endpoint, boundType, false, null, OPEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns everything below the endpoint relative to the specified comparator,
|
||||
* with the specified endpoint behavior.
|
||||
*/
|
||||
static <T> GeneralRange<T> upTo(Comparator<? super T> comparator, @Nullable T endpoint, BoundType boundType) {
|
||||
return new GeneralRange<T>(comparator, false, null, OPEN, true, endpoint, boundType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns everything between the endpoints relative to the specified
|
||||
* comparator, with the specified endpoint behavior.
|
||||
*/
|
||||
static <T> GeneralRange<T> range(Comparator<? super T> comparator, @Nullable T lower, BoundType lowerType,
|
||||
@Nullable T upper, BoundType upperType) {
|
||||
return new GeneralRange<T>(comparator, true, lower, lowerType, true, upper, upperType);
|
||||
}
|
||||
|
||||
private final Comparator<? super T> comparator;
|
||||
private final boolean hasLowerBound;
|
||||
@Nullable
|
||||
private final T lowerEndpoint;
|
||||
private final BoundType lowerBoundType;
|
||||
private final boolean hasUpperBound;
|
||||
@Nullable
|
||||
private final T upperEndpoint;
|
||||
private final BoundType upperBoundType;
|
||||
|
||||
private GeneralRange(Comparator<? super T> comparator, boolean hasLowerBound, @Nullable T lowerEndpoint,
|
||||
BoundType lowerBoundType, boolean hasUpperBound, @Nullable T upperEndpoint, BoundType upperBoundType) {
|
||||
this.comparator = checkNotNull(comparator);
|
||||
this.hasLowerBound = hasLowerBound;
|
||||
this.hasUpperBound = hasUpperBound;
|
||||
this.lowerEndpoint = lowerEndpoint;
|
||||
this.lowerBoundType = checkNotNull(lowerBoundType);
|
||||
this.upperEndpoint = upperEndpoint;
|
||||
this.upperBoundType = checkNotNull(upperBoundType);
|
||||
|
||||
if (hasLowerBound) {
|
||||
comparator.compare(lowerEndpoint, lowerEndpoint);
|
||||
}
|
||||
if (hasUpperBound) {
|
||||
comparator.compare(upperEndpoint, upperEndpoint);
|
||||
}
|
||||
if (hasLowerBound && hasUpperBound) {
|
||||
int cmp = comparator.compare(lowerEndpoint, upperEndpoint);
|
||||
// be consistent with Range
|
||||
checkArgument(cmp <= 0, "lowerEndpoint (%s) > upperEndpoint (%s)", lowerEndpoint, upperEndpoint);
|
||||
if (cmp == 0) {
|
||||
checkArgument(lowerBoundType != OPEN | upperBoundType != OPEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Comparator<? super T> comparator() {
|
||||
return comparator;
|
||||
}
|
||||
|
||||
boolean hasLowerBound() {
|
||||
return hasLowerBound;
|
||||
}
|
||||
|
||||
boolean hasUpperBound() {
|
||||
return hasUpperBound;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return (hasUpperBound() && tooLow(getUpperEndpoint())) || (hasLowerBound() && tooHigh(getLowerEndpoint()));
|
||||
}
|
||||
|
||||
boolean tooLow(@Nullable T t) {
|
||||
if (!hasLowerBound()) {
|
||||
return false;
|
||||
}
|
||||
T lbound = getLowerEndpoint();
|
||||
int cmp = comparator.compare(t, lbound);
|
||||
return cmp < 0 | (cmp == 0 & getLowerBoundType() == OPEN);
|
||||
}
|
||||
|
||||
boolean tooHigh(@Nullable T t) {
|
||||
if (!hasUpperBound()) {
|
||||
return false;
|
||||
}
|
||||
T ubound = getUpperEndpoint();
|
||||
int cmp = comparator.compare(t, ubound);
|
||||
return cmp > 0 | (cmp == 0 & getUpperBoundType() == OPEN);
|
||||
}
|
||||
|
||||
boolean contains(@Nullable T t) {
|
||||
return !tooLow(t) && !tooHigh(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the intersection of the two ranges, or an empty range if their
|
||||
* intersection is empty.
|
||||
*/
|
||||
GeneralRange<T> intersect(GeneralRange<T> other) {
|
||||
checkNotNull(other);
|
||||
checkArgument(comparator.equals(other.comparator));
|
||||
|
||||
boolean hasLowBound = this.hasLowerBound;
|
||||
@Nullable
|
||||
T lowEnd = getLowerEndpoint();
|
||||
BoundType lowType = getLowerBoundType();
|
||||
if (!hasLowerBound()) {
|
||||
hasLowBound = other.hasLowerBound;
|
||||
lowEnd = other.getLowerEndpoint();
|
||||
lowType = other.getLowerBoundType();
|
||||
} else if (other.hasLowerBound()) {
|
||||
int cmp = comparator.compare(getLowerEndpoint(), other.getLowerEndpoint());
|
||||
if (cmp < 0 || (cmp == 0 && other.getLowerBoundType() == OPEN)) {
|
||||
lowEnd = other.getLowerEndpoint();
|
||||
lowType = other.getLowerBoundType();
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasUpBound = this.hasUpperBound;
|
||||
@Nullable
|
||||
T upEnd = getUpperEndpoint();
|
||||
BoundType upType = getUpperBoundType();
|
||||
if (!hasUpperBound()) {
|
||||
hasUpBound = other.hasUpperBound;
|
||||
upEnd = other.getUpperEndpoint();
|
||||
upType = other.getUpperBoundType();
|
||||
} else if (other.hasUpperBound()) {
|
||||
int cmp = comparator.compare(getUpperEndpoint(), other.getUpperEndpoint());
|
||||
if (cmp > 0 || (cmp == 0 && other.getUpperBoundType() == OPEN)) {
|
||||
upEnd = other.getUpperEndpoint();
|
||||
upType = other.getUpperBoundType();
|
||||
}
|
||||
}
|
||||
|
||||
if (hasLowBound && hasUpBound) {
|
||||
int cmp = comparator.compare(lowEnd, upEnd);
|
||||
if (cmp > 0 || (cmp == 0 && lowType == OPEN && upType == OPEN)) {
|
||||
// force allowed empty range
|
||||
lowEnd = upEnd;
|
||||
lowType = OPEN;
|
||||
upType = CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
return new GeneralRange<T>(comparator, hasLowBound, lowEnd, lowType, hasUpBound, upEnd, upType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof GeneralRange) {
|
||||
GeneralRange<?> r = (GeneralRange<?>) obj;
|
||||
return comparator.equals(r.comparator) && hasLowerBound == r.hasLowerBound
|
||||
&& hasUpperBound == r.hasUpperBound && getLowerBoundType().equals(r.getLowerBoundType())
|
||||
&& getUpperBoundType().equals(r.getUpperBoundType())
|
||||
&& Objects.equal(getLowerEndpoint(), r.getLowerEndpoint())
|
||||
&& Objects.equal(getUpperEndpoint(), r.getUpperEndpoint());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(comparator, getLowerEndpoint(), getLowerBoundType(), getUpperEndpoint(),
|
||||
getUpperBoundType());
|
||||
}
|
||||
|
||||
private transient GeneralRange<T> reverse;
|
||||
|
||||
/**
|
||||
* Returns the same range relative to the reversed comparator.
|
||||
*/
|
||||
GeneralRange<T> reverse() {
|
||||
GeneralRange<T> result = reverse;
|
||||
if (result == null) {
|
||||
result = new GeneralRange<T>(Ordering.from(comparator).reverse(), hasUpperBound, getUpperEndpoint(),
|
||||
getUpperBoundType(), hasLowerBound, getLowerEndpoint(), getLowerBoundType());
|
||||
result.reverse = this;
|
||||
return this.reverse = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append(comparator).append(":").append(lowerBoundType == CLOSED ? '[' : '(')
|
||||
.append(hasLowerBound ? lowerEndpoint : "-\u221e").append(',')
|
||||
.append(hasUpperBound ? upperEndpoint : "\u221e").append(upperBoundType == CLOSED ? ']' : ')')
|
||||
.toString();
|
||||
}
|
||||
|
||||
T getLowerEndpoint() {
|
||||
return lowerEndpoint;
|
||||
}
|
||||
|
||||
BoundType getLowerBoundType() {
|
||||
return lowerBoundType;
|
||||
}
|
||||
|
||||
T getUpperEndpoint() {
|
||||
return upperEndpoint;
|
||||
}
|
||||
|
||||
BoundType getUpperBoundType() {
|
||||
return upperBoundType;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.google.common.collect;
|
||||
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* Private replacement for {@link com.google.gwt.user.client.rpc.GwtTransient}
|
||||
* to work around build-system quirks. This annotation should be used
|
||||
* <b>only</b> in {@code com.google.common.collect}.
|
||||
*/
|
||||
@Documented
|
||||
@GwtCompatible
|
||||
@Retention(RUNTIME)
|
||||
@Target(FIELD)
|
||||
@interface GwtTransient {
|
||||
}
|
154
sources/main/java/com/google/common/collect/HashBasedTable.java
Normal file
154
sources/main/java/com/google/common/collect/HashBasedTable.java
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Table} using hash tables.
|
||||
*
|
||||
* <p>
|
||||
* The views returned by {@link #column}, {@link #columnKeySet()}, and
|
||||
* {@link #columnMap()} have iterators that don't support {@code remove()}.
|
||||
* Otherwise, all optional operations are supported. Null row keys, columns
|
||||
* keys, and values are not supported.
|
||||
*
|
||||
* <p>
|
||||
* Lookups by row key are often faster than lookups by column key, because the
|
||||
* data is stored in a {@code Map<R, Map<C, V>>}. A method call like {@code
|
||||
* column(columnKey).get(rowKey)} still runs quickly, since the row key is
|
||||
* provided. However, {@code column(columnKey).size()} takes longer, since an
|
||||
* iteration across all row keys occurs.
|
||||
*
|
||||
* <p>
|
||||
* Note that this implementation is not synchronized. If multiple threads access
|
||||
* this table concurrently and one of the threads modifies the table, it must be
|
||||
* synchronized externally.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table">
|
||||
* {@code Table}</a>.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @since 7.0
|
||||
*/
|
||||
@GwtCompatible(serializable = true)
|
||||
public class HashBasedTable<R, C, V> extends StandardTable<R, C, V> {
|
||||
private static class Factory<C, V> implements Supplier<Map<C, V>>, Serializable {
|
||||
final int expectedSize;
|
||||
|
||||
Factory(int expectedSize) {
|
||||
this.expectedSize = expectedSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<C, V> get() {
|
||||
return Maps.newHashMapWithExpectedSize(expectedSize);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty {@code HashBasedTable}.
|
||||
*/
|
||||
public static <R, C, V> HashBasedTable<R, C, V> create() {
|
||||
return new HashBasedTable<R, C, V>(new HashMap<R, Map<C, V>>(), new Factory<C, V>(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty {@code HashBasedTable} with the specified map sizes.
|
||||
*
|
||||
* @param expectedRows the expected number of distinct row keys
|
||||
* @param expectedCellsPerRow the expected number of column key / value mappings
|
||||
* in each row
|
||||
* @throws IllegalArgumentException if {@code expectedRows} or {@code
|
||||
* expectedCellsPerRow} is negative
|
||||
*/
|
||||
public static <R, C, V> HashBasedTable<R, C, V> create(int expectedRows, int expectedCellsPerRow) {
|
||||
checkNonnegative(expectedCellsPerRow, "expectedCellsPerRow");
|
||||
Map<R, Map<C, V>> backingMap = Maps.newHashMapWithExpectedSize(expectedRows);
|
||||
return new HashBasedTable<R, C, V>(backingMap, new Factory<C, V>(expectedCellsPerRow));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code HashBasedTable} with the same mappings as the specified
|
||||
* table.
|
||||
*
|
||||
* @param table the table to copy
|
||||
* @throws NullPointerException if any of the row keys, column keys, or values
|
||||
* in {@code table} is null
|
||||
*/
|
||||
public static <R, C, V> HashBasedTable<R, C, V> create(Table<? extends R, ? extends C, ? extends V> table) {
|
||||
HashBasedTable<R, C, V> result = create();
|
||||
result.putAll(table);
|
||||
return result;
|
||||
}
|
||||
|
||||
HashBasedTable(Map<R, Map<C, V>> backingMap, Factory<C, V> factory) {
|
||||
super(backingMap, factory);
|
||||
}
|
||||
|
||||
// Overriding so NullPointerTester test passes.
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
return super.contains(rowKey, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsColumn(@Nullable Object columnKey) {
|
||||
return super.containsColumn(columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsRow(@Nullable Object rowKey) {
|
||||
return super.containsRow(rowKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@Nullable Object value) {
|
||||
return super.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
return super.get(rowKey, columnKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(@Nullable Object rowKey, @Nullable Object columnKey) {
|
||||
return super.remove(rowKey, columnKey);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
670
sources/main/java/com/google/common/collect/HashBiMap.java
Normal file
670
sources/main/java/com/google/common/collect/HashBiMap.java
Normal file
@ -0,0 +1,670 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
|
||||
import static com.google.common.collect.CollectPreconditions.checkRemove;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Arrays;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* A {@link BiMap} backed by two hash tables. This implementation allows null
|
||||
* keys and values. A {@code HashBiMap} and its inverse are both serializable.
|
||||
*
|
||||
* <p>
|
||||
* See the Guava User Guide article on <a href=
|
||||
* "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
|
||||
* {@code BiMap} </a>.
|
||||
*
|
||||
* @author Louis Wasserman
|
||||
* @author Mike Bostock
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
public final class HashBiMap<K, V> extends AbstractMap<K, V> implements BiMap<K, V>, Serializable {
|
||||
|
||||
/**
|
||||
* Returns a new, empty {@code HashBiMap} with the default initial capacity
|
||||
* (16).
|
||||
*/
|
||||
public static <K, V> HashBiMap<K, V> create() {
|
||||
return create(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new, empty bimap with the specified expected size.
|
||||
*
|
||||
* @param expectedSize the expected number of entries
|
||||
* @throws IllegalArgumentException if the specified expected size is negative
|
||||
*/
|
||||
public static <K, V> HashBiMap<K, V> create(int expectedSize) {
|
||||
return new HashBiMap<K, V>(expectedSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new bimap containing initial values from {@code map}. The bimap
|
||||
* is created with an initial capacity sufficient to hold the mappings in the
|
||||
* specified map.
|
||||
*/
|
||||
public static <K, V> HashBiMap<K, V> create(Map<? extends K, ? extends V> map) {
|
||||
HashBiMap<K, V> bimap = create(map.size());
|
||||
bimap.putAll(map);
|
||||
return bimap;
|
||||
}
|
||||
|
||||
private static final class BiEntry<K, V> extends ImmutableEntry<K, V> {
|
||||
final int keyHash;
|
||||
final int valueHash;
|
||||
|
||||
@Nullable
|
||||
BiEntry<K, V> nextInKToVBucket;
|
||||
|
||||
@Nullable
|
||||
BiEntry<K, V> nextInVToKBucket;
|
||||
|
||||
BiEntry(K key, int keyHash, V value, int valueHash) {
|
||||
super(key, value);
|
||||
this.keyHash = keyHash;
|
||||
this.valueHash = valueHash;
|
||||
}
|
||||
}
|
||||
|
||||
private static final double LOAD_FACTOR = 1.0;
|
||||
|
||||
private transient BiEntry<K, V>[] hashTableKToV;
|
||||
private transient BiEntry<K, V>[] hashTableVToK;
|
||||
private transient int size;
|
||||
private transient int mask;
|
||||
private transient int modCount;
|
||||
|
||||
private HashBiMap(int expectedSize) {
|
||||
init(expectedSize);
|
||||
}
|
||||
|
||||
private void init(int expectedSize) {
|
||||
checkNonnegative(expectedSize, "expectedSize");
|
||||
int tableSize = Hashing.closedTableSize(expectedSize, LOAD_FACTOR);
|
||||
this.hashTableKToV = createTable(tableSize);
|
||||
this.hashTableVToK = createTable(tableSize);
|
||||
this.mask = tableSize - 1;
|
||||
this.modCount = 0;
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and removes {@code entry} from the bucket linked lists in both the
|
||||
* key-to-value direction and the value-to-key direction.
|
||||
*/
|
||||
private void delete(BiEntry<K, V> entry) {
|
||||
int keyBucket = entry.keyHash & mask;
|
||||
BiEntry<K, V> prevBucketEntry = null;
|
||||
for (BiEntry<K, V> bucketEntry = hashTableKToV[keyBucket]; true; bucketEntry = bucketEntry.nextInKToVBucket) {
|
||||
if (bucketEntry == entry) {
|
||||
if (prevBucketEntry == null) {
|
||||
hashTableKToV[keyBucket] = entry.nextInKToVBucket;
|
||||
} else {
|
||||
prevBucketEntry.nextInKToVBucket = entry.nextInKToVBucket;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prevBucketEntry = bucketEntry;
|
||||
}
|
||||
|
||||
int valueBucket = entry.valueHash & mask;
|
||||
prevBucketEntry = null;
|
||||
for (BiEntry<K, V> bucketEntry = hashTableVToK[valueBucket];; bucketEntry = bucketEntry.nextInVToKBucket) {
|
||||
if (bucketEntry == entry) {
|
||||
if (prevBucketEntry == null) {
|
||||
hashTableVToK[valueBucket] = entry.nextInVToKBucket;
|
||||
} else {
|
||||
prevBucketEntry.nextInVToKBucket = entry.nextInVToKBucket;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prevBucketEntry = bucketEntry;
|
||||
}
|
||||
|
||||
size--;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
private void insert(BiEntry<K, V> entry) {
|
||||
int keyBucket = entry.keyHash & mask;
|
||||
entry.nextInKToVBucket = hashTableKToV[keyBucket];
|
||||
hashTableKToV[keyBucket] = entry;
|
||||
|
||||
int valueBucket = entry.valueHash & mask;
|
||||
entry.nextInVToKBucket = hashTableVToK[valueBucket];
|
||||
hashTableVToK[valueBucket] = entry;
|
||||
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
private static int hash(@Nullable Object o) {
|
||||
return Hashing.smear((o == null) ? 0 : o.hashCode());
|
||||
}
|
||||
|
||||
private BiEntry<K, V> seekByKey(@Nullable Object key, int keyHash) {
|
||||
for (BiEntry<K, V> entry = hashTableKToV[keyHash & mask]; entry != null; entry = entry.nextInKToVBucket) {
|
||||
if (keyHash == entry.keyHash && Objects.equal(key, entry.key)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private BiEntry<K, V> seekByValue(@Nullable Object value, int valueHash) {
|
||||
for (BiEntry<K, V> entry = hashTableVToK[valueHash & mask]; entry != null; entry = entry.nextInVToKBucket) {
|
||||
if (valueHash == entry.valueHash && Objects.equal(value, entry.value)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(@Nullable Object key) {
|
||||
return seekByKey(key, hash(key)) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@Nullable Object value) {
|
||||
return seekByValue(value, hash(value)) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public V get(@Nullable Object key) {
|
||||
BiEntry<K, V> entry = seekByKey(key, hash(key));
|
||||
return (entry == null) ? null : entry.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(@Nullable K key, @Nullable V value) {
|
||||
return put(key, value, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V forcePut(@Nullable K key, @Nullable V value) {
|
||||
return put(key, value, true);
|
||||
}
|
||||
|
||||
private V put(@Nullable K key, @Nullable V value, boolean force) {
|
||||
int keyHash = hash(key);
|
||||
int valueHash = hash(value);
|
||||
|
||||
BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
|
||||
if (oldEntryForKey != null && valueHash == oldEntryForKey.valueHash
|
||||
&& Objects.equal(value, oldEntryForKey.value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
|
||||
if (oldEntryForValue != null) {
|
||||
if (force) {
|
||||
delete(oldEntryForValue);
|
||||
} else {
|
||||
throw new IllegalArgumentException("value already present: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldEntryForKey != null) {
|
||||
delete(oldEntryForKey);
|
||||
}
|
||||
BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
|
||||
insert(newEntry);
|
||||
rehashIfNecessary();
|
||||
return (oldEntryForKey == null) ? null : oldEntryForKey.value;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private K putInverse(@Nullable V value, @Nullable K key, boolean force) {
|
||||
int valueHash = hash(value);
|
||||
int keyHash = hash(key);
|
||||
|
||||
BiEntry<K, V> oldEntryForValue = seekByValue(value, valueHash);
|
||||
if (oldEntryForValue != null && keyHash == oldEntryForValue.keyHash
|
||||
&& Objects.equal(key, oldEntryForValue.key)) {
|
||||
return key;
|
||||
}
|
||||
|
||||
BiEntry<K, V> oldEntryForKey = seekByKey(key, keyHash);
|
||||
if (oldEntryForKey != null) {
|
||||
if (force) {
|
||||
delete(oldEntryForKey);
|
||||
} else {
|
||||
throw new IllegalArgumentException("value already present: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
if (oldEntryForValue != null) {
|
||||
delete(oldEntryForValue);
|
||||
}
|
||||
BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, value, valueHash);
|
||||
insert(newEntry);
|
||||
rehashIfNecessary();
|
||||
return (oldEntryForValue == null) ? null : oldEntryForValue.key;
|
||||
}
|
||||
|
||||
private void rehashIfNecessary() {
|
||||
BiEntry<K, V>[] oldKToV = hashTableKToV;
|
||||
if (Hashing.needsResizing(size, oldKToV.length, LOAD_FACTOR)) {
|
||||
int newTableSize = oldKToV.length * 2;
|
||||
|
||||
this.hashTableKToV = createTable(newTableSize);
|
||||
this.hashTableVToK = createTable(newTableSize);
|
||||
this.mask = newTableSize - 1;
|
||||
this.size = 0;
|
||||
|
||||
for (int bucket = 0; bucket < oldKToV.length; bucket++) {
|
||||
BiEntry<K, V> entry = oldKToV[bucket];
|
||||
while (entry != null) {
|
||||
BiEntry<K, V> nextEntry = entry.nextInKToVBucket;
|
||||
insert(entry);
|
||||
entry = nextEntry;
|
||||
}
|
||||
}
|
||||
this.modCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private BiEntry<K, V>[] createTable(int length) {
|
||||
return new BiEntry[length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(@Nullable Object key) {
|
||||
BiEntry<K, V> entry = seekByKey(key, hash(key));
|
||||
if (entry == null) {
|
||||
return null;
|
||||
} else {
|
||||
delete(entry);
|
||||
return entry.value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
size = 0;
|
||||
Arrays.fill(hashTableKToV, null);
|
||||
Arrays.fill(hashTableVToK, null);
|
||||
modCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
abstract class Itr<T> implements Iterator<T> {
|
||||
int nextBucket = 0;
|
||||
BiEntry<K, V> next = null;
|
||||
BiEntry<K, V> toRemove = null;
|
||||
int expectedModCount = modCount;
|
||||
|
||||
private void checkForConcurrentModification() {
|
||||
if (modCount != expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
checkForConcurrentModification();
|
||||
if (next != null) {
|
||||
return true;
|
||||
}
|
||||
while (nextBucket < hashTableKToV.length) {
|
||||
if (hashTableKToV[nextBucket] != null) {
|
||||
next = hashTableKToV[nextBucket++];
|
||||
return true;
|
||||
}
|
||||
nextBucket++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
checkForConcurrentModification();
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
BiEntry<K, V> entry = next;
|
||||
next = entry.nextInKToVBucket;
|
||||
toRemove = entry;
|
||||
return output(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
checkForConcurrentModification();
|
||||
checkRemove(toRemove != null);
|
||||
delete(toRemove);
|
||||
expectedModCount = modCount;
|
||||
toRemove = null;
|
||||
}
|
||||
|
||||
abstract T output(BiEntry<K, V> entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return new KeySet();
|
||||
}
|
||||
|
||||
private final class KeySet extends Maps.KeySet<K, V> {
|
||||
KeySet() {
|
||||
super(HashBiMap.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<K> iterator() {
|
||||
return new Itr<K>() {
|
||||
@Override
|
||||
K output(BiEntry<K, V> entry) {
|
||||
return entry.key;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(@Nullable Object o) {
|
||||
BiEntry<K, V> entry = seekByKey(o, hash(o));
|
||||
if (entry == null) {
|
||||
return false;
|
||||
} else {
|
||||
delete(entry);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> values() {
|
||||
return inverse().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
private final class EntrySet extends Maps.EntrySet<K, V> {
|
||||
@Override
|
||||
Map<K, V> map() {
|
||||
return HashBiMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<K, V>> iterator() {
|
||||
return new Itr<Entry<K, V>>() {
|
||||
@Override
|
||||
Entry<K, V> output(BiEntry<K, V> entry) {
|
||||
return new MapEntry(entry);
|
||||
}
|
||||
|
||||
class MapEntry extends AbstractMapEntry<K, V> {
|
||||
BiEntry<K, V> delegate;
|
||||
|
||||
MapEntry(BiEntry<K, V> entry) {
|
||||
this.delegate = entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return delegate.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return delegate.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
V oldValue = delegate.value;
|
||||
int valueHash = hash(value);
|
||||
if (valueHash == delegate.valueHash && Objects.equal(value, oldValue)) {
|
||||
return value;
|
||||
}
|
||||
checkArgument(seekByValue(value, valueHash) == null, "value already present: %s", value);
|
||||
delete(delegate);
|
||||
BiEntry<K, V> newEntry = new BiEntry<K, V>(delegate.key, delegate.keyHash, value, valueHash);
|
||||
insert(newEntry);
|
||||
expectedModCount = modCount;
|
||||
if (toRemove == delegate) {
|
||||
toRemove = newEntry;
|
||||
}
|
||||
delegate = newEntry;
|
||||
return oldValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private transient BiMap<V, K> inverse;
|
||||
|
||||
@Override
|
||||
public BiMap<V, K> inverse() {
|
||||
return (inverse == null) ? inverse = new Inverse() : inverse;
|
||||
}
|
||||
|
||||
private final class Inverse extends AbstractMap<V, K> implements BiMap<V, K>, Serializable {
|
||||
BiMap<K, V> forward() {
|
||||
return HashBiMap.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
forward().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(@Nullable Object value) {
|
||||
return forward().containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K get(@Nullable Object value) {
|
||||
BiEntry<K, V> entry = seekByValue(value, hash(value));
|
||||
return (entry == null) ? null : entry.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K put(@Nullable V value, @Nullable K key) {
|
||||
return putInverse(value, key, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K forcePut(@Nullable V value, @Nullable K key) {
|
||||
return putInverse(value, key, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K remove(@Nullable Object value) {
|
||||
BiEntry<K, V> entry = seekByValue(value, hash(value));
|
||||
if (entry == null) {
|
||||
return null;
|
||||
} else {
|
||||
delete(entry);
|
||||
return entry.key;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiMap<K, V> inverse() {
|
||||
return forward();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<V> keySet() {
|
||||
return new InverseKeySet();
|
||||
}
|
||||
|
||||
private final class InverseKeySet extends Maps.KeySet<V, K> {
|
||||
InverseKeySet() {
|
||||
super(Inverse.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(@Nullable Object o) {
|
||||
BiEntry<K, V> entry = seekByValue(o, hash(o));
|
||||
if (entry == null) {
|
||||
return false;
|
||||
} else {
|
||||
delete(entry);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return new Itr<V>() {
|
||||
@Override
|
||||
V output(BiEntry<K, V> entry) {
|
||||
return entry.value;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> values() {
|
||||
return forward().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<V, K>> entrySet() {
|
||||
return new Maps.EntrySet<V, K>() {
|
||||
|
||||
@Override
|
||||
Map<V, K> map() {
|
||||
return Inverse.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<V, K>> iterator() {
|
||||
return new Itr<Entry<V, K>>() {
|
||||
@Override
|
||||
Entry<V, K> output(BiEntry<K, V> entry) {
|
||||
return new InverseEntry(entry);
|
||||
}
|
||||
|
||||
class InverseEntry extends AbstractMapEntry<V, K> {
|
||||
BiEntry<K, V> delegate;
|
||||
|
||||
InverseEntry(BiEntry<K, V> entry) {
|
||||
this.delegate = entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getKey() {
|
||||
return delegate.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getValue() {
|
||||
return delegate.key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public K setValue(K key) {
|
||||
K oldKey = delegate.key;
|
||||
int keyHash = hash(key);
|
||||
if (keyHash == delegate.keyHash && Objects.equal(key, oldKey)) {
|
||||
return key;
|
||||
}
|
||||
checkArgument(seekByKey(key, keyHash) == null, "value already present: %s", key);
|
||||
delete(delegate);
|
||||
BiEntry<K, V> newEntry = new BiEntry<K, V>(key, keyHash, delegate.value,
|
||||
delegate.valueHash);
|
||||
insert(newEntry);
|
||||
expectedModCount = modCount;
|
||||
// This is safe because entries can only get bumped up to earlier in the
|
||||
// iteration,
|
||||
// so they can't get revisited.
|
||||
return oldKey;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Object writeReplace() {
|
||||
return new InverseSerializedForm<K, V>(HashBiMap.this);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class InverseSerializedForm<K, V> implements Serializable {
|
||||
private final HashBiMap<K, V> bimap;
|
||||
|
||||
InverseSerializedForm(HashBiMap<K, V> bimap) {
|
||||
this.bimap = bimap;
|
||||
}
|
||||
|
||||
Object readResolve() {
|
||||
return bimap.inverse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData the number of entries, first key, first value, second key, second
|
||||
* value, and so on.
|
||||
*/
|
||||
@GwtIncompatible("java.io.ObjectOutputStream")
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
Serialization.writeMap(this, stream);
|
||||
}
|
||||
|
||||
@GwtIncompatible("java.io.ObjectInputStream")
|
||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
int size = Serialization.readCount(stream);
|
||||
init(size);
|
||||
Serialization.populateMap(this, stream, size);
|
||||
}
|
||||
|
||||
@GwtIncompatible("Not needed in emulated source")
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
143
sources/main/java/com/google/common/collect/HashMultimap.java
Normal file
143
sources/main/java/com/google/common/collect/HashMultimap.java
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* Implementation of {@link Multimap} using hash tables.
|
||||
*
|
||||
* <p>
|
||||
* The multimap does not store duplicate key-value pairs. Adding a new key-value
|
||||
* pair equal to an existing key-value pair has no effect.
|
||||
*
|
||||
* <p>
|
||||
* Keys and values may be null. All optional multimap methods are supported, and
|
||||
* all returned views are modifiable.
|
||||
*
|
||||
* <p>
|
||||
* This class is not threadsafe when any concurrent operations update the
|
||||
* multimap. Concurrent read operations will work correctly. To allow concurrent
|
||||
* update operations, wrap your multimap with a call to
|
||||
* {@link Multimaps#synchronizedSetMultimap}.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible(serializable = true, emulated = true)
|
||||
public final class HashMultimap<K, V> extends AbstractSetMultimap<K, V> {
|
||||
private static final int DEFAULT_VALUES_PER_KEY = 2;
|
||||
|
||||
@VisibleForTesting
|
||||
transient int expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
|
||||
|
||||
/**
|
||||
* Creates a new, empty {@code HashMultimap} with the default initial
|
||||
* capacities.
|
||||
*/
|
||||
public static <K, V> HashMultimap<K, V> create() {
|
||||
return new HashMultimap<K, V>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty {@code HashMultimap} with enough capacity to hold the
|
||||
* specified numbers of keys and values without rehashing.
|
||||
*
|
||||
* @param expectedKeys the expected number of distinct keys
|
||||
* @param expectedValuesPerKey the expected average number of values per key
|
||||
* @throws IllegalArgumentException if {@code expectedKeys} or {@code
|
||||
* expectedValuesPerKey} is negative
|
||||
*/
|
||||
public static <K, V> HashMultimap<K, V> create(int expectedKeys, int expectedValuesPerKey) {
|
||||
return new HashMultimap<K, V>(expectedKeys, expectedValuesPerKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code HashMultimap} with the same mappings as the specified
|
||||
* multimap. If a key-value mapping appears multiple times in the input
|
||||
* multimap, it only appears once in the constructed multimap.
|
||||
*
|
||||
* @param multimap the multimap whose contents are copied to this multimap
|
||||
*/
|
||||
public static <K, V> HashMultimap<K, V> create(Multimap<? extends K, ? extends V> multimap) {
|
||||
return new HashMultimap<K, V>(multimap);
|
||||
}
|
||||
|
||||
private HashMultimap() {
|
||||
super(new HashMap<K, Collection<V>>());
|
||||
}
|
||||
|
||||
private HashMultimap(int expectedKeys, int expectedValuesPerKey) {
|
||||
super(Maps.<K, Collection<V>>newHashMapWithExpectedSize(expectedKeys));
|
||||
Preconditions.checkArgument(expectedValuesPerKey >= 0);
|
||||
this.expectedValuesPerKey = expectedValuesPerKey;
|
||||
}
|
||||
|
||||
private HashMultimap(Multimap<? extends K, ? extends V> multimap) {
|
||||
super(Maps.<K, Collection<V>>newHashMapWithExpectedSize(multimap.keySet().size()));
|
||||
putAll(multimap);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Creates an empty {@code HashSet} for a collection of values for one key.
|
||||
*
|
||||
* @return a new {@code HashSet} containing a collection of values for one key
|
||||
*/
|
||||
@Override
|
||||
Set<V> createCollection() {
|
||||
return Sets.<V>newHashSetWithExpectedSize(expectedValuesPerKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData expectedValuesPerKey, number of distinct keys, and then for each
|
||||
* distinct key: the key, number of values for that key, and the
|
||||
* key's values
|
||||
*/
|
||||
@GwtIncompatible("java.io.ObjectOutputStream")
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
stream.writeInt(expectedValuesPerKey);
|
||||
Serialization.writeMultimap(this, stream);
|
||||
}
|
||||
|
||||
@GwtIncompatible("java.io.ObjectInputStream")
|
||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
expectedValuesPerKey = stream.readInt();
|
||||
int distinctKeys = Serialization.readCount(stream);
|
||||
Map<K, Collection<V>> map = Maps.newHashMapWithExpectedSize(distinctKeys);
|
||||
setMap(map);
|
||||
Serialization.populateMultimap(this, stream, distinctKeys);
|
||||
}
|
||||
|
||||
@GwtIncompatible("Not needed in emulated source")
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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 com.google.common.collect;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* Multiset implementation backed by a {@link HashMap}.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Jared Levy
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible(serializable = true, emulated = true)
|
||||
public final class HashMultiset<E> extends AbstractMapBasedMultiset<E> {
|
||||
|
||||
/**
|
||||
* Creates a new, empty {@code HashMultiset} using the default initial capacity.
|
||||
*/
|
||||
public static <E> HashMultiset<E> create() {
|
||||
return new HashMultiset<E>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new, empty {@code HashMultiset} with the specified expected number
|
||||
* of distinct elements.
|
||||
*
|
||||
* @param distinctElements the expected number of distinct elements
|
||||
* @throws IllegalArgumentException if {@code distinctElements} is negative
|
||||
*/
|
||||
public static <E> HashMultiset<E> create(int distinctElements) {
|
||||
return new HashMultiset<E>(distinctElements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code HashMultiset} containing the specified elements.
|
||||
*
|
||||
* <p>
|
||||
* This implementation is highly efficient when {@code elements} is itself a
|
||||
* {@link Multiset}.
|
||||
*
|
||||
* @param elements the elements that the multiset should contain
|
||||
*/
|
||||
public static <E> HashMultiset<E> create(Iterable<? extends E> elements) {
|
||||
HashMultiset<E> multiset = create(Multisets.inferDistinctElements(elements));
|
||||
Iterables.addAll(multiset, elements);
|
||||
return multiset;
|
||||
}
|
||||
|
||||
private HashMultiset() {
|
||||
super(new HashMap<E, Count>());
|
||||
}
|
||||
|
||||
private HashMultiset(int distinctElements) {
|
||||
super(Maps.<E, Count>newHashMapWithExpectedSize(distinctElements));
|
||||
}
|
||||
|
||||
/**
|
||||
* @serialData the number of distinct elements, the first element, its count,
|
||||
* the second element, its count, and so on
|
||||
*/
|
||||
@GwtIncompatible("java.io.ObjectOutputStream")
|
||||
private void writeObject(ObjectOutputStream stream) throws IOException {
|
||||
stream.defaultWriteObject();
|
||||
Serialization.writeMultiset(this, stream);
|
||||
}
|
||||
|
||||
@GwtIncompatible("java.io.ObjectInputStream")
|
||||
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||
stream.defaultReadObject();
|
||||
int distinctElements = Serialization.readCount(stream);
|
||||
setBackingMap(Maps.<E, Count>newHashMapWithExpectedSize(distinctElements));
|
||||
Serialization.populateMultiset(this, stream, distinctElements);
|
||||
}
|
||||
|
||||
@GwtIncompatible("Not needed in emulated source.")
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
74
sources/main/java/com/google/common/collect/Hashing.java
Normal file
74
sources/main/java/com/google/common/collect/Hashing.java
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
/**
|
||||
* Static methods for implementing hash-based collections.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @author Jesse Wilson
|
||||
* @author Austin Appleby
|
||||
*/
|
||||
@GwtCompatible
|
||||
final class Hashing {
|
||||
private Hashing() {
|
||||
}
|
||||
|
||||
private static final int C1 = 0xcc9e2d51;
|
||||
private static final int C2 = 0x1b873593;
|
||||
|
||||
/*
|
||||
* This method was rewritten in Java from an intermediate step of the Murmur
|
||||
* hash function in
|
||||
* http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp, which
|
||||
* contained the following header:
|
||||
*
|
||||
* MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
* domain. The author hereby disclaims copyright to this source code.
|
||||
*/
|
||||
static int smear(int hashCode) {
|
||||
return C2 * Integer.rotateLeft(hashCode * C1, 15);
|
||||
}
|
||||
|
||||
static int smearedHash(@Nullable Object o) {
|
||||
return smear((o == null) ? 0 : o.hashCode());
|
||||
}
|
||||
|
||||
private static int MAX_TABLE_SIZE = Ints.MAX_POWER_OF_TWO;
|
||||
|
||||
static int closedTableSize(int expectedEntries, double loadFactor) {
|
||||
// Get the recommended table size.
|
||||
// Round down to the nearest power of 2.
|
||||
expectedEntries = Math.max(expectedEntries, 2);
|
||||
int tableSize = Integer.highestOneBit(expectedEntries);
|
||||
// Check to make sure that we will not exceed the maximum load factor.
|
||||
if (expectedEntries > (int) (loadFactor * tableSize)) {
|
||||
tableSize <<= 1;
|
||||
return (tableSize > 0) ? tableSize : MAX_TABLE_SIZE;
|
||||
}
|
||||
return tableSize;
|
||||
}
|
||||
|
||||
static boolean needsResizing(int size, int tableSize, double loadFactor) {
|
||||
return size > loadFactor * tableSize && tableSize < MAX_TABLE_SIZE;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
import com.google.common.annotations.GwtIncompatible;
|
||||
|
||||
/**
|
||||
* List returned by {@link ImmutableCollection#asList} that delegates
|
||||
* {@code contains} checks to the backing collection.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @author Louis Wasserman
|
||||
*/
|
||||
@GwtCompatible(serializable = true, emulated = true)
|
||||
@SuppressWarnings("serial")
|
||||
abstract class ImmutableAsList<E> extends ImmutableList<E> {
|
||||
abstract ImmutableCollection<E> delegateCollection();
|
||||
|
||||
@Override
|
||||
public boolean contains(Object target) {
|
||||
// The collection's contains() is at least as fast as ImmutableList's
|
||||
// and is often faster.
|
||||
return delegateCollection().contains(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegateCollection().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegateCollection().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isPartialView() {
|
||||
return delegateCollection().isPartialView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized form that leads to the same performance as the original list.
|
||||
*/
|
||||
@GwtIncompatible("serialization")
|
||||
static class SerializedForm implements Serializable {
|
||||
final ImmutableCollection<?> collection;
|
||||
|
||||
SerializedForm(ImmutableCollection<?> collection) {
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
Object readResolve() {
|
||||
return collection.asList();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
@GwtIncompatible("serialization")
|
||||
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
|
||||
throw new InvalidObjectException("Use SerializedForm");
|
||||
}
|
||||
|
||||
@GwtIncompatible("serialization")
|
||||
@Override
|
||||
Object writeReplace() {
|
||||
return new SerializedForm(delegateCollection());
|
||||
}
|
||||
}
|
281
sources/main/java/com/google/common/collect/ImmutableBiMap.java
Normal file
281
sources/main/java/com/google/common/collect/ImmutableBiMap.java
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* An immutable {@link BiMap} with reliable user-specified iteration order. Does
|
||||
* not permit null keys or values. An {@code ImmutableBiMap} and its inverse
|
||||
* have the same iteration ordering.
|
||||
*
|
||||
* <p>
|
||||
* An instance of {@code ImmutableBiMap} contains its own data and will
|
||||
* <i>never</i> change. {@code ImmutableBiMap} is convenient for
|
||||
* {@code public static final} maps ("constant maps") and also lets you easily
|
||||
* make a "defensive copy" of a bimap provided to your class by a caller.
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> Although this class is not final, it cannot be subclassed as it
|
||||
* has no public or protected constructors. Thus, instances of this class are
|
||||
* guaranteed to be immutable.
|
||||
*
|
||||
* @author Jared Levy
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible(serializable = true, emulated = true)
|
||||
public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V> implements BiMap<K, V> {
|
||||
|
||||
/**
|
||||
* Returns the empty bimap.
|
||||
*/
|
||||
// Casting to any type is safe because the set will never hold any elements.
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <K, V> ImmutableBiMap<K, V> of() {
|
||||
return (ImmutableBiMap<K, V>) EmptyImmutableBiMap.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable bimap containing a single entry.
|
||||
*/
|
||||
public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {
|
||||
return new SingletonImmutableBiMap<K, V>(k1, v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the given entries, in order.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys or values are added
|
||||
*/
|
||||
public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) {
|
||||
return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the given entries, in order.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys or values are added
|
||||
*/
|
||||
public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
|
||||
return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the given entries, in order.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys or values are added
|
||||
*/
|
||||
public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
|
||||
return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the given entries, in order.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys or values are added
|
||||
*/
|
||||
public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
|
||||
return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4),
|
||||
entryOf(k5, v5));
|
||||
}
|
||||
|
||||
// looking for of() with > 5 entries? Use the builder instead.
|
||||
|
||||
/**
|
||||
* Returns a new builder. The generated builder is equivalent to the builder
|
||||
* created by the {@link Builder} constructor.
|
||||
*/
|
||||
public static <K, V> Builder<K, V> builder() {
|
||||
return new Builder<K, V>();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for creating immutable bimap instances, especially {@code public
|
||||
* static final} bimaps ("constant bimaps"). Example:
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* @code
|
||||
*
|
||||
* static final ImmutableBiMap<String, Integer> WORD_TO_INT = new ImmutableBiMap.Builder<String, Integer>()
|
||||
* .put("one", 1).put("two", 2).put("three", 3).build();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods
|
||||
* are even more convenient.
|
||||
*
|
||||
* <p>
|
||||
* Builder instances can be reused - it is safe to call {@link #build} multiple
|
||||
* times to build multiple bimaps in series. Each bimap is a superset of the
|
||||
* bimaps created before it.
|
||||
*
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> {
|
||||
|
||||
/**
|
||||
* Creates a new builder. The returned builder is equivalent to the builder
|
||||
* generated by {@link ImmutableBiMap#builder}.
|
||||
*/
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates {@code key} with {@code value} in the built bimap. Duplicate keys
|
||||
* or values are not allowed, and will cause {@link #build} to fail.
|
||||
*/
|
||||
@Override
|
||||
public Builder<K, V> put(K key, V value) {
|
||||
super.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates all of the given map's keys and values in the built bimap.
|
||||
* Duplicate keys or values are not allowed, and will cause {@link #build} to
|
||||
* fail.
|
||||
*
|
||||
* @throws NullPointerException if any key or value in {@code map} is null
|
||||
*/
|
||||
@Override
|
||||
public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
|
||||
super.putAll(map);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a newly-created immutable bimap.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys or values were added
|
||||
*/
|
||||
@Override
|
||||
public ImmutableBiMap<K, V> build() {
|
||||
switch (size) {
|
||||
case 0:
|
||||
return of();
|
||||
case 1:
|
||||
return of(entries[0].getKey(), entries[0].getValue());
|
||||
default:
|
||||
return new RegularImmutableBiMap<K, V>(size, entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable bimap containing the same entries as {@code map}. If
|
||||
* {@code map} somehow contains entries with duplicate keys (for example, if it
|
||||
* is a {@code SortedMap} whose comparator is not <i>consistent with
|
||||
* equals</i>), the results of this method are undefined.
|
||||
*
|
||||
* <p>
|
||||
* Despite the method name, this method attempts to avoid actually copying the
|
||||
* data when it is safe to do so. The exact circumstances under which a copy
|
||||
* will or will not be performed are undocumented and subject to change.
|
||||
*
|
||||
* @throws IllegalArgumentException if two keys have the same value
|
||||
* @throws NullPointerException if any key or value in {@code map} is null
|
||||
*/
|
||||
public static <K, V> ImmutableBiMap<K, V> copyOf(Map<? extends K, ? extends V> map) {
|
||||
if (map instanceof ImmutableBiMap) {
|
||||
@SuppressWarnings("unchecked") // safe since map is not writable
|
||||
ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map;
|
||||
// TODO(user): if we need to make a copy of a BiMap because the
|
||||
// forward map is a view, don't make a copy of the non-view delegate map
|
||||
if (!bimap.isPartialView()) {
|
||||
return bimap;
|
||||
}
|
||||
}
|
||||
Entry<?, ?>[] entries = map.entrySet().toArray(EMPTY_ENTRY_ARRAY);
|
||||
switch (entries.length) {
|
||||
case 0:
|
||||
return of();
|
||||
case 1:
|
||||
@SuppressWarnings("unchecked") // safe covariant cast in this context
|
||||
Entry<K, V> entry = (Entry<K, V>) entries[0];
|
||||
return of(entry.getKey(), entry.getValue());
|
||||
default:
|
||||
return new RegularImmutableBiMap<K, V>(entries);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];
|
||||
|
||||
ImmutableBiMap() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* The inverse of an {@code ImmutableBiMap} is another {@code ImmutableBiMap}.
|
||||
*/
|
||||
@Override
|
||||
public abstract ImmutableBiMap<V, K> inverse();
|
||||
|
||||
/**
|
||||
* Returns an immutable set of the values in this map. The values are in the
|
||||
* same order as the parameters used to build this map.
|
||||
*/
|
||||
@Override
|
||||
public ImmutableSet<V> values() {
|
||||
return inverse().keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the bimap unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public V forcePut(K key, V value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized type for all ImmutableBiMap instances. It captures the logical
|
||||
* contents and they are reconstructed using public factory methods. This
|
||||
* ensures that the implementation types remain as implementation details.
|
||||
*
|
||||
* Since the bimap is immutable, ImmutableBiMap doesn't require special logic
|
||||
* for keeping the bimap and its inverse in sync during serialization, the way
|
||||
* AbstractBiMap does.
|
||||
*/
|
||||
private static class SerializedForm extends ImmutableMap.SerializedForm {
|
||||
SerializedForm(ImmutableBiMap<?, ?> bimap) {
|
||||
super(bimap);
|
||||
}
|
||||
|
||||
@Override
|
||||
Object readResolve() {
|
||||
Builder<Object, Object> builder = new Builder<Object, Object>();
|
||||
return createMap(builder);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
Object writeReplace() {
|
||||
return new SerializedForm(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2009 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.primitives.Primitives;
|
||||
|
||||
/**
|
||||
* A class-to-instance map backed by an {@link ImmutableMap}. See also
|
||||
* {@link MutableClassToInstanceMap}.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
public final class ImmutableClassToInstanceMap<B> extends ForwardingMap<Class<? extends B>, B>
|
||||
implements ClassToInstanceMap<B>, Serializable {
|
||||
|
||||
/**
|
||||
* Returns a new builder. The generated builder is equivalent to the builder
|
||||
* created by the {@link Builder} constructor.
|
||||
*/
|
||||
public static <B> Builder<B> builder() {
|
||||
return new Builder<B>();
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for creating immutable class-to-instance maps. Example:
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* @code
|
||||
*
|
||||
* static final ImmutableClassToInstanceMap<Handler> HANDLERS = new ImmutableClassToInstanceMap.Builder<Handler>()
|
||||
* .put(FooHandler.class, new FooHandler()).put(BarHandler.class, new SubBarHandler())
|
||||
* .put(Handler.class, new QuuxHandler()).build();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* After invoking {@link #build()} it is still possible to add more entries and
|
||||
* build again. Thus each map generated by this builder will be a superset of
|
||||
* any map generated before it.
|
||||
*
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
public static final class Builder<B> {
|
||||
private final ImmutableMap.Builder<Class<? extends B>, B> mapBuilder = ImmutableMap.builder();
|
||||
|
||||
/**
|
||||
* Associates {@code key} with {@code value} in the built map. Duplicate keys
|
||||
* are not allowed, and will cause {@link #build} to fail.
|
||||
*/
|
||||
public <T extends B> Builder<B> put(Class<T> key, T value) {
|
||||
mapBuilder.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates all of {@code map's} keys and values in the built map. Duplicate
|
||||
* keys are not allowed, and will cause {@link #build} to fail.
|
||||
*
|
||||
* @throws NullPointerException if any key or value in {@code map} is null
|
||||
* @throws ClassCastException if any value is not an instance of the type
|
||||
* specified by its key
|
||||
*/
|
||||
public <T extends B> Builder<B> putAll(Map<? extends Class<? extends T>, ? extends T> map) {
|
||||
for (Entry<? extends Class<? extends T>, ? extends T> entry : map.entrySet()) {
|
||||
Class<? extends T> type = entry.getKey();
|
||||
T value = entry.getValue();
|
||||
mapBuilder.put(type, cast(type, value));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private static <B, T extends B> T cast(Class<T> type, B value) {
|
||||
return Primitives.wrap(type).cast(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new immutable class-to-instance map containing the entries provided
|
||||
* to this builder.
|
||||
*
|
||||
* @throws IllegalArgumentException if duplicate keys were added
|
||||
*/
|
||||
public ImmutableClassToInstanceMap<B> build() {
|
||||
return new ImmutableClassToInstanceMap<B>(mapBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing the same entries as {@code map}. If
|
||||
* {@code map} somehow contains entries with duplicate keys (for example, if it
|
||||
* is a {@code SortedMap} whose comparator is not <i>consistent with
|
||||
* equals</i>), the results of this method are undefined.
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> Despite what the method name suggests, if {@code map} is an
|
||||
* {@code ImmutableClassToInstanceMap}, no copy will actually be performed.
|
||||
*
|
||||
* @throws NullPointerException if any key or value in {@code map} is null
|
||||
* @throws ClassCastException if any value is not an instance of the type
|
||||
* specified by its key
|
||||
*/
|
||||
public static <B, S extends B> ImmutableClassToInstanceMap<B> copyOf(
|
||||
Map<? extends Class<? extends S>, ? extends S> map) {
|
||||
if (map instanceof ImmutableClassToInstanceMap) {
|
||||
@SuppressWarnings("unchecked") // covariant casts safe (unmodifiable)
|
||||
// Eclipse won't compile if we cast to the parameterized type.
|
||||
ImmutableClassToInstanceMap<B> cast = (ImmutableClassToInstanceMap) map;
|
||||
return cast;
|
||||
}
|
||||
return new Builder<B>().putAll(map).build();
|
||||
}
|
||||
|
||||
private final ImmutableMap<Class<? extends B>, B> delegate;
|
||||
|
||||
private ImmutableClassToInstanceMap(ImmutableMap<Class<? extends B>, B> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Class<? extends B>, B> delegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // value could not get in if not a T
|
||||
@Nullable
|
||||
public <T extends B> T getInstance(Class<T> type) {
|
||||
return (T) delegate.get(checkNotNull(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the map unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public <T extends B> T putInstance(Class<T> type, T value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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 com.google.common.collect;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
|
||||
import static com.google.common.collect.ObjectArrays.checkElementsNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.GwtCompatible;
|
||||
|
||||
/**
|
||||
* An immutable collection. Does not permit null elements.
|
||||
*
|
||||
* <p>
|
||||
* In addition to the {@link Collection} methods, this class has an
|
||||
* {@link #asList()} method, which returns a list view of the collection's
|
||||
* elements.
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> Although this class is not final, it cannot be subclassed
|
||||
* outside of this package as it has no public or protected constructors. Thus,
|
||||
* instances of this type are guaranteed to be immutable.
|
||||
*
|
||||
* @author Jesse Wilson
|
||||
* @since 2.0 (imported from Google Collections Library)
|
||||
*/
|
||||
@GwtCompatible(emulated = true)
|
||||
@SuppressWarnings("serial") // we're overriding default serialization
|
||||
public abstract class ImmutableCollection<E> extends AbstractCollection<E> implements Serializable {
|
||||
|
||||
ImmutableCollection() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable iterator across the elements in this collection.
|
||||
*/
|
||||
@Override
|
||||
public abstract UnmodifiableIterator<E> iterator();
|
||||
|
||||
@Override
|
||||
public final Object[] toArray() {
|
||||
int size = size();
|
||||
if (size == 0) {
|
||||
return ObjectArrays.EMPTY_ARRAY;
|
||||
}
|
||||
Object[] result = new Object[size()];
|
||||
copyIntoArray(result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T> T[] toArray(T[] other) {
|
||||
checkNotNull(other);
|
||||
int size = size();
|
||||
if (other.length < size) {
|
||||
other = ObjectArrays.newArray(other, size);
|
||||
} else if (other.length > size) {
|
||||
other[size] = null;
|
||||
}
|
||||
copyIntoArray(other, 0);
|
||||
return other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@Nullable Object object) {
|
||||
return object != null && super.contains(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean add(E e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean remove(Object object) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean addAll(Collection<? extends E> newElements) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean removeAll(Collection<?> oldElements) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final boolean retainAll(Collection<?> elementsToKeep) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guaranteed to throw an exception and leave the collection unmodified.
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @deprecated Unsupported operation.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public final void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(kevinb): Restructure code so ImmutableList doesn't contain this
|
||||
* variable, which it doesn't use.
|
||||
*/
|
||||
private transient ImmutableList<E> asList;
|
||||
|
||||
/**
|
||||
* Returns a list view of the collection.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public ImmutableList<E> asList() {
|
||||
ImmutableList<E> list = asList;
|
||||
return (list == null) ? (asList = createAsList()) : list;
|
||||
}
|
||||
|
||||
ImmutableList<E> createAsList() {
|
||||
switch (size()) {
|
||||
case 0:
|
||||
return ImmutableList.of();
|
||||
case 1:
|
||||
return ImmutableList.of(iterator().next());
|
||||
default:
|
||||
return new RegularImmutableAsList<E>(this, toArray());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this immutable collection's implementation contains
|
||||
* references to user-created objects that aren't accessible via this
|
||||
* collection's methods. This is generally used to determine whether
|
||||
* {@code copyOf} implementations should make an explicit copy to avoid memory
|
||||
* leaks.
|
||||
*/
|
||||
abstract boolean isPartialView();
|
||||
|
||||
/**
|
||||
* Copies the contents of this immutable collection into the specified array at
|
||||
* the specified offset. Returns {@code offset + size()}.
|
||||
*/
|
||||
int copyIntoArray(Object[] dst, int offset) {
|
||||
for (E e : this) {
|
||||
dst[offset++] = e;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
Object writeReplace() {
|
||||
// We serialize by default to ImmutableList, the simplest thing that works.
|
||||
return new ImmutableList.SerializedForm(toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base class for builders of {@link ImmutableCollection} types.
|
||||
*
|
||||
* @since 10.0
|
||||
*/
|
||||
public abstract static class Builder<E> {
|
||||
static final int DEFAULT_INITIAL_CAPACITY = 4;
|
||||
|
||||
static int expandedCapacity(int oldCapacity, int minCapacity) {
|
||||
if (minCapacity < 0) {
|
||||
throw new AssertionError("cannot store more than MAX_VALUE elements");
|
||||
}
|
||||
// careful of overflow!
|
||||
int newCapacity = oldCapacity + (oldCapacity >> 1) + 1;
|
||||
if (newCapacity < minCapacity) {
|
||||
newCapacity = Integer.highestOneBit(minCapacity - 1) << 1;
|
||||
}
|
||||
if (newCapacity < 0) {
|
||||
newCapacity = Integer.MAX_VALUE;
|
||||
// guaranteed to be >= newCapacity
|
||||
}
|
||||
return newCapacity;
|
||||
}
|
||||
|
||||
Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@code element} to the {@code ImmutableCollection} being built.
|
||||
*
|
||||
* <p>
|
||||
* Note that each builder class covariantly returns its own type from this
|
||||
* method.
|
||||
*
|
||||
* @param element the element to add
|
||||
* @return this {@code Builder} instance
|
||||
* @throws NullPointerException if {@code element} is null
|
||||
*/
|
||||
public abstract Builder<E> add(E element);
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableCollection}
|
||||
* being built.
|
||||
*
|
||||
* <p>
|
||||
* Note that each builder class overrides this method in order to covariantly
|
||||
* return its own type.
|
||||
*
|
||||
* @param elements the elements to add
|
||||
* @return this {@code Builder} instance
|
||||
* @throws NullPointerException if {@code elements} is null or contains a null
|
||||
* element
|
||||
*/
|
||||
public Builder<E> add(E... elements) {
|
||||
for (E element : elements) {
|
||||
add(element);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableCollection}
|
||||
* being built.
|
||||
*
|
||||
* <p>
|
||||
* Note that each builder class overrides this method in order to covariantly
|
||||
* return its own type.
|
||||
*
|
||||
* @param elements the elements to add
|
||||
* @return this {@code Builder} instance
|
||||
* @throws NullPointerException if {@code elements} is null or contains a null
|
||||
* element
|
||||
*/
|
||||
public Builder<E> addAll(Iterable<? extends E> elements) {
|
||||
for (E element : elements) {
|
||||
add(element);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each element of {@code elements} to the {@code ImmutableCollection}
|
||||
* being built.
|
||||
*
|
||||
* <p>
|
||||
* Note that each builder class overrides this method in order to covariantly
|
||||
* return its own type.
|
||||
*
|
||||
* @param elements the elements to add
|
||||
* @return this {@code Builder} instance
|
||||
* @throws NullPointerException if {@code elements} is null or contains a null
|
||||
* element
|
||||
*/
|
||||
public Builder<E> addAll(Iterator<? extends E> elements) {
|
||||
while (elements.hasNext()) {
|
||||
add(elements.next());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a newly-created {@code ImmutableCollection} of the appropriate type,
|
||||
* containing the elements provided to this builder.
|
||||
*
|
||||
* <p>
|
||||
* Note that each builder class covariantly returns the appropriate type of
|
||||
* {@code ImmutableCollection} from this method.
|
||||
*/
|
||||
public abstract ImmutableCollection<E> build();
|
||||
}
|
||||
|
||||
abstract static class ArrayBasedBuilder<E> extends ImmutableCollection.Builder<E> {
|
||||
Object[] contents;
|
||||
int size;
|
||||
|
||||
ArrayBasedBuilder(int initialCapacity) {
|
||||
checkNonnegative(initialCapacity, "initialCapacity");
|
||||
this.contents = new Object[initialCapacity];
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the absolute capacity of the builder so it can accept at least the
|
||||
* specified number of elements without being resized.
|
||||
*/
|
||||
private void ensureCapacity(int minCapacity) {
|
||||
if (contents.length < minCapacity) {
|
||||
this.contents = ObjectArrays.arraysCopyOf(this.contents,
|
||||
expandedCapacity(contents.length, minCapacity));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayBasedBuilder<E> add(E element) {
|
||||
checkNotNull(element);
|
||||
ensureCapacity(size + 1);
|
||||
contents[size++] = element;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<E> add(E... elements) {
|
||||
checkElementsNotNull(elements);
|
||||
ensureCapacity(size + elements.length);
|
||||
System.arraycopy(elements, 0, contents, size, elements.length);
|
||||
size += elements.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<E> addAll(Iterable<? extends E> elements) {
|
||||
if (elements instanceof Collection) {
|
||||
Collection<?> collection = (Collection<?>) elements;
|
||||
ensureCapacity(size + collection.size());
|
||||
}
|
||||
super.addAll(elements);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user