com.github.rinde.rinsim.util.LinkedHashBiMap Maven / Gradle / Ivy
/*
* Copyright (C) 2011-2017 Rinde van Lon, imec-DistriNet, KU Leuven
*
* 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.github.rinde.rinsim.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.BiMap;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Iterators;
import com.google.common.collect.Maps;
/**
* {@link BiMap} with key based insertion ordering. Note that all its collection
* views are unmodifiable.
*
* @author Rinde van Lon
* @param Key type.
* @param Value type.
*/
public class LinkedHashBiMap extends ForwardingBiMap {
final BiMap delegateBiMap;
final Set set;
@Nullable
private BiMap inverse;
LinkedHashBiMap() {
delegateBiMap = HashBiMap.create();
set = new LinkedHashSet<>();
}
// views are unmodifiable
@Override
public Set values() {
return new OrderedValuesSet<>(set, delegateBiMap);
}
@Override
public Set keySet() {
return Collections.unmodifiableSet(set);
}
@Override
public Set> entrySet() {
return new EntrySet<>(set, delegateBiMap);
}
// modifications
@Override
public V put(@Nullable K key, @Nullable V value) {
final V v = delegate().put(key, value);
set.add(key);
return v;
}
@Override
public V forcePut(@Nullable K key, @Nullable V value) {
final V v = delegate().forcePut(key, value);
set.add(key);
return v;
}
@Override
public void putAll(@Nullable Map extends K, ? extends V> map) {
if (map == null) {
return;
}
for (final Entry extends K, ? extends V> entry : map.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public V remove(@Nullable Object key) {
final V val = delegate().remove(key);
set.remove(key);
return val;
}
@Override
public void clear() {
delegate().clear();
set.clear();
}
@Override
public BiMap inverse() {
final BiMap inv = inverse;
return inv == null ? inverse = new Inverse() : inv;
}
@Override
protected BiMap delegate() {
return delegateBiMap;
}
public static LinkedHashBiMap create() {
return new LinkedHashBiMap<>();
}
private final class Inverse extends ForwardingBiMap {
Inverse() {}
BiMap forward() {
return LinkedHashBiMap.this;
}
@Override
public BiMap inverse() {
return forward();
}
// views are unmodifiable
@Override
public Set values() {
return forward().keySet();
}
@Override
public Set keySet() {
return forward().values();
}
@Override
@Deprecated
public Set> entrySet() {
throw new UnsupportedOperationException(
"Use inverse().entrySet() instead.");
}
// modifications
@Override
public K put(@Nullable V key, @Nullable K value) {
final K val = get(key);
forward().put(value, key);
return val;
}
@Override
public K forcePut(@Nullable V key, @Nullable K value) {
final K val = get(key);
forward().forcePut(value, key);
return val;
}
@Override
public void putAll(@Nullable Map extends V, ? extends K> map) {
if (map == null) {
return;
}
for (final Entry extends V, ? extends K> entry : map.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
protected BiMap delegate() {
return delegateBiMap.inverse();
}
}
private static final class OrderedValuesSet extends UnmodifiableSet {
final Set ordering;
final BiMap delegateMap;
OrderedValuesSet(Set order, BiMap delegate) {
ordering = order;
delegateMap = delegate;
}
@Override
public Iterator iterator() {
final Iterator it = ordering.iterator();
return new AbstractIterator() {
@Override
protected V computeNext() {
if (it.hasNext()) {
return delegateMap.get(it.next());
}
return super.endOfData();
}
};
}
@Override
public Object[] toArray() {
return Iterators.toArray(iterator(), Object.class);
}
@Override
public T[] toArray(@Nullable T[] a) {
final List list = new ArrayList<>(size());
Iterators.addAll(list, iterator());
return list.toArray(a);
}
@Override
protected Set delegate() {
return delegateMap.values();
}
}
private static final class EntrySet extends
UnmodifiableSet> {
final Map delegateSet;
private final Set ordering;
EntrySet(Set order, Map map) {
ordering = order;
delegateSet = map;
}
@Override
protected Set> delegate() {
return delegateSet.entrySet();
}
@Override
public Iterator> iterator() {
final Iterator it = ordering.iterator();
return new AbstractIterator>() {
@Override
protected Map.Entry computeNext() {
if (it.hasNext()) {
final A key = it.next();
return Maps.immutableEntry(key, delegateSet.get(key));
}
return super.endOfData();
}
};
}
@Override
public Object[] toArray() {
return Iterators.toArray(iterator(), Entry.class);
}
@Override
public T[] toArray(@Nullable T[] a) {
final List> list = new ArrayList<>(size());
Iterators.addAll(list, iterator());
return list.toArray(a);
}
}
private abstract static class UnmodifiableSet extends ForwardingSet {
UnmodifiableSet() {}
@Override
@Deprecated
public boolean add(@Nullable T e) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public boolean remove(@Nullable Object o) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public boolean addAll(@Nullable Collection extends T> c) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public boolean retainAll(@Nullable Collection> c) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public boolean removeAll(@Nullable Collection> c) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public void clear() {
throw new UnsupportedOperationException();
}
}
}