/* * Copyright 2015 Goldman Sachs. * * 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.gs.collections.impl.bimap.immutable; import java.io.Serializable; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; import com.gs.collections.api.bag.ImmutableBag; import com.gs.collections.api.bag.primitive.ImmutableBooleanBag; import com.gs.collections.api.bag.primitive.ImmutableByteBag; import com.gs.collections.api.bag.primitive.ImmutableCharBag; import com.gs.collections.api.bag.primitive.ImmutableDoubleBag; import com.gs.collections.api.bag.primitive.ImmutableFloatBag; import com.gs.collections.api.bag.primitive.ImmutableIntBag; import com.gs.collections.api.bag.primitive.ImmutableLongBag; import com.gs.collections.api.bag.primitive.ImmutableShortBag; import com.gs.collections.api.bimap.ImmutableBiMap; import com.gs.collections.api.block.function.Function; import com.gs.collections.api.block.function.Function0; import com.gs.collections.api.block.function.Function2; import com.gs.collections.api.block.function.primitive.BooleanFunction; import com.gs.collections.api.block.function.primitive.ByteFunction; import com.gs.collections.api.block.function.primitive.CharFunction; import com.gs.collections.api.block.function.primitive.DoubleFunction; import com.gs.collections.api.block.function.primitive.FloatFunction; import com.gs.collections.api.block.function.primitive.IntFunction; import com.gs.collections.api.block.function.primitive.LongFunction; import com.gs.collections.api.block.function.primitive.ShortFunction; import com.gs.collections.api.block.predicate.Predicate; import com.gs.collections.api.block.predicate.Predicate2; import com.gs.collections.api.block.procedure.Procedure; import com.gs.collections.api.block.procedure.Procedure2; import com.gs.collections.api.map.ImmutableMap; import com.gs.collections.api.map.MutableMap; import com.gs.collections.api.multimap.set.ImmutableSetMultimap; import com.gs.collections.api.partition.set.PartitionImmutableSet; import com.gs.collections.api.partition.set.PartitionMutableSet; import com.gs.collections.api.set.ImmutableSet; import com.gs.collections.api.set.MutableSet; import com.gs.collections.api.tuple.Pair; import com.gs.collections.impl.bimap.AbstractBiMap; import com.gs.collections.impl.bimap.mutable.HashBiMap; import com.gs.collections.impl.block.factory.Predicates; import com.gs.collections.impl.block.procedure.PartitionProcedure; import com.gs.collections.impl.block.procedure.SelectInstancesOfProcedure; import com.gs.collections.impl.factory.BiMaps; import com.gs.collections.impl.factory.Sets; import com.gs.collections.impl.list.fixed.ArrayAdapter; import com.gs.collections.impl.multimap.set.UnifiedSetMultimap; import com.gs.collections.impl.partition.set.PartitionUnifiedSet; import com.gs.collections.impl.set.mutable.UnifiedSet; import com.gs.collections.impl.utility.MapIterate; public abstract class AbstractImmutableBiMap<K, V> extends AbstractBiMap<K, V> implements ImmutableBiMap<K, V>, Map<K, V> { private final ImmutableMap<K, V> delegate; private final AbstractImmutableBiMap<V, K> inverse; private AbstractImmutableBiMap(ImmutableMap<K, V> delegate, AbstractImmutableBiMap<V, K> valuesToKeys) { this.delegate = delegate; this.inverse = valuesToKeys; } AbstractImmutableBiMap(ImmutableMap<K, V> map, ImmutableMap<V, K> inverse) { this.delegate = map; this.inverse = new Inverse<V, K>(inverse, this); } @Override protected ImmutableMap<K, V> getDelegate() { return this.delegate; } @Override protected ImmutableMap<V, K> getInverse() { return this.inverse.delegate; } public ImmutableBiMap<K, V> newWithKeyValue(K key, V value) { HashBiMap<K, V> map = new HashBiMap<K, V>(this.delegate.castToMap()); map.put(key, value); return map.toImmutable(); } public ImmutableBiMap<K, V> newWithAllKeyValues(Iterable<? extends Pair<? extends K, ? extends V>> keyValues) { HashBiMap<K, V> map = new HashBiMap<K, V>(this.delegate.castToMap()); for (Pair<? extends K, ? extends V> keyValuePair : keyValues) { map.put(keyValuePair.getOne(), keyValuePair.getTwo()); } return map.toImmutable(); } public ImmutableBiMap<K, V> newWithAllKeyValueArguments(Pair<? extends K, ? extends V>... keyValuePairs) { return this.newWithAllKeyValues(ArrayAdapter.adapt(keyValuePairs)); } public ImmutableBiMap<K, V> newWithoutKey(K key) { HashBiMap<K, V> map = new HashBiMap<K, V>(this.delegate.castToMap()); map.removeKey(key); return map.toImmutable(); } public ImmutableBiMap<K, V> newWithoutAllKeys(Iterable<? extends K> keys) { HashBiMap<K, V> map = new HashBiMap<K, V>(this.delegate.castToMap()); for (K key : keys) { map.removeKey(key); } return map.toImmutable(); } public ImmutableBiMap<V, K> inverse() { return this.inverse; } public ImmutableSetMultimap<V, K> flip() { // TODO: We could optimize this since we know the values are unique return MapIterate.flip(this).toImmutable(); } public ImmutableBiMap<V, K> flipUniqueValues() { return this.inverse(); } public V put(K key, V value) { throw new UnsupportedOperationException("Cannot call put() on " + this.getClass().getSimpleName()); } public void putAll(Map<? extends K, ? extends V> map) { throw new UnsupportedOperationException("Cannot call putAll() on " + this.getClass().getSimpleName()); } public V remove(Object key) { throw new UnsupportedOperationException("Cannot call remove() on " + this.getClass().getSimpleName()); } public void clear() { throw new UnsupportedOperationException("Cannot call clear() on " + this.getClass().getSimpleName()); } public Set<K> keySet() { return this.delegate.castToMap().keySet(); } public Collection<V> values() { return this.delegate.castToMap().values(); } public Set<Map.Entry<K, V>> entrySet() { return this.delegate.castToMap().entrySet(); } public Iterator<V> iterator() { return this.delegate.iterator(); } public ImmutableBiMap<K, V> toImmutable() { return this; } public Map<K, V> castToMap() { return this; } public MutableMap<K, V> toMap() { return this.getDelegate().toMap(); } public <K2, V2> ImmutableBiMap<K2, V2> collect(Function2<? super K, ? super V, Pair<K2, V2>> function) { ImmutableMap<K2, V2> result = this.delegate.collect(function); return BiMaps.immutable.withAll(result); } public <VV> ImmutableBag<VV> collect(Function<? super V, ? extends VV> function) { return this.delegate.collect(function); } public <R> ImmutableBiMap<K, R> collectValues(Function2<? super K, ? super V, ? extends R> function) { ImmutableMap<K, R> result = this.delegate.collectValues(function); return BiMaps.immutable.withAll(result); } public ImmutableBooleanBag collectBoolean(BooleanFunction<? super V> booleanFunction) { return this.delegate.collectBoolean(booleanFunction); } public ImmutableByteBag collectByte(ByteFunction<? super V> byteFunction) { return this.delegate.collectByte(byteFunction); } public ImmutableCharBag collectChar(CharFunction<? super V> charFunction) { return this.delegate.collectChar(charFunction); } public ImmutableDoubleBag collectDouble(DoubleFunction<? super V> doubleFunction) { return this.delegate.collectDouble(doubleFunction); } public ImmutableFloatBag collectFloat(FloatFunction<? super V> floatFunction) { return this.delegate.collectFloat(floatFunction); } public ImmutableIntBag collectInt(IntFunction<? super V> intFunction) { return this.delegate.collectInt(intFunction); } public ImmutableLongBag collectLong(LongFunction<? super V> longFunction) { return this.delegate.collectLong(longFunction); } public ImmutableShortBag collectShort(ShortFunction<? super V> shortFunction) { return this.delegate.collectShort(shortFunction); } public <P, VV> ImmutableBag<VV> collectWith(Function2<? super V, ? super P, ? extends VV> function, P parameter) { return this.delegate.collectWith(function, parameter); } public <VV> ImmutableBag<VV> collectIf(Predicate<? super V> predicate, Function<? super V, ? extends VV> function) { return this.delegate.collectIf(predicate, function); } public <VV> ImmutableBag<VV> flatCollect(Function<? super V, ? extends Iterable<VV>> function) { return this.delegate.flatCollect(function); } public ImmutableBiMap<K, V> select(Predicate2<? super K, ? super V> predicate) { return MapIterate.selectMapOnEntry(this, predicate, HashBiMap.<K, V>newMap()).toImmutable(); } public ImmutableBiMap<K, V> tap(Procedure<? super V> procedure) { this.forEach(procedure); return this; } public ImmutableSet<V> select(Predicate<? super V> predicate) { return this.delegate.select(predicate, Sets.mutable.<V>empty()).toImmutable(); } public <P> ImmutableSet<V> selectWith(Predicate2<? super V, ? super P> predicate, P parameter) { return this.delegate.selectWith(predicate, parameter, Sets.mutable.<V>empty()).toImmutable(); } public ImmutableBiMap<K, V> reject(Predicate2<? super K, ? super V> predicate) { return MapIterate.rejectMapOnEntry(this, predicate, HashBiMap.<K, V>newMap()).toImmutable(); } public ImmutableSet<V> reject(Predicate<? super V> predicate) { return this.delegate.reject(predicate, Sets.mutable.<V>empty()).toImmutable(); } public <P> ImmutableSet<V> rejectWith(Predicate2<? super V, ? super P> predicate, P parameter) { return this.delegate.rejectWith(predicate, parameter, Sets.mutable.<V>empty()).toImmutable(); } public PartitionImmutableSet<V> partition(Predicate<? super V> predicate) { PartitionMutableSet<V> result = new PartitionUnifiedSet<V>(); this.inverse.forEachKey(new PartitionProcedure<V>(predicate, result)); return result.toImmutable(); } public <P> PartitionImmutableSet<V> partitionWith(Predicate2<? super V, ? super P> predicate, P parameter) { return this.partition(Predicates.bind(predicate, parameter)); } public <S> ImmutableSet<Pair<V, S>> zip(Iterable<S> that) { return this.delegate.zip(that, new UnifiedSet<Pair<V, S>>()).toImmutable(); } public ImmutableSet<Pair<V, Integer>> zipWithIndex() { return this.delegate.zipWithIndex(new UnifiedSet<Pair<V, Integer>>()).toImmutable(); } public <VV> ImmutableSetMultimap<VV, V> groupBy(Function<? super V, ? extends VV> function) { return this.delegate.groupBy(function, new UnifiedSetMultimap<VV, V>()).toImmutable(); } public <VV> ImmutableSetMultimap<VV, V> groupByEach(Function<? super V, ? extends Iterable<VV>> function) { return this.delegate.groupByEach(function, new UnifiedSetMultimap<VV, V>()).toImmutable(); } public <VV> ImmutableBiMap<VV, V> groupByUniqueKey(Function<? super V, ? extends VV> function) { return BiMaps.immutable.withAll(this.delegate.groupByUniqueKey(function)); } public <K2, V2> ImmutableMap<K2, V2> aggregateBy(Function<? super V, ? extends K2> groupBy, Function0<? extends V2> zeroValueFactory, Function2<? super V2, ? super V, ? extends V2> nonMutatingAggregator) { return this.delegate.aggregateBy(groupBy, zeroValueFactory, nonMutatingAggregator); } public <K2, V2> ImmutableMap<K2, V2> aggregateInPlaceBy(Function<? super V, ? extends K2> groupBy, Function0<? extends V2> zeroValueFactory, Procedure2<? super V2, ? super V> mutatingAggregator) { return this.delegate.aggregateInPlaceBy(groupBy, zeroValueFactory, mutatingAggregator); } public <S> ImmutableSet<S> selectInstancesOf(Class<S> clazz) { MutableSet<S> result = new UnifiedSet<S>(); this.inverse.forEachKey(new SelectInstancesOfProcedure<S>(clazz, result)); return result.toImmutable(); } private static class Inverse<K, V> extends AbstractImmutableBiMap<K, V> implements Serializable { Inverse(ImmutableMap<K, V> delegate, AbstractImmutableBiMap<V, K> inverse) { super(delegate, inverse); } protected Object writeReplace() { return new ImmutableBiMapSerializationProxy<K, V>(this); } } }