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;
|
||||
}
|
Reference in New Issue
Block a user