/*
* 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.facebook.presto.util.maps;
import com.google.common.base.Equivalence;
import com.google.common.collect.Iterators;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import static java.util.stream.Collectors.joining;
public class IdentityLinkedHashMap<K, V>
implements Map<K, V>
{
private final Map<Equivalence.Wrapper<K>, V> delegate = new LinkedHashMap<>();
private final Equivalence<Object> equivalence = Equivalence.identity();
public IdentityLinkedHashMap()
{
}
public IdentityLinkedHashMap(IdentityLinkedHashMap<K, V> map)
{
putAll(map);
}
@Override
public int size()
{
return delegate.size();
}
@Override
public boolean isEmpty()
{
return delegate.isEmpty();
}
@Override
public boolean containsKey(Object key)
{
return delegate.containsKey(equivalence.wrap(key));
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean containsValue(Object value)
{
// should use identity-based comparison
throw new UnsupportedOperationException();
}
@Override
public V get(Object key)
{
return delegate.get(equivalence.wrap(key));
}
@Override
public V put(K key, V value)
{
return delegate.put(equivalence.wrap(key), value);
}
@Override
public V remove(Object key)
{
return delegate.remove(equivalence.wrap(key));
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean remove(Object key, Object value)
{
// should use identity-based comparison for value too
throw new UnsupportedOperationException();
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean replace(K key, V oldValue, V newValue)
{
// should use identity-based comparison for value too
throw new UnsupportedOperationException();
}
@Override
public void putAll(Map<? extends K, ? extends V> map)
{
map.entrySet().forEach(e -> delegate.put(equivalence.wrap(e.getKey()), e.getValue()));
}
@Override
public void clear()
{
delegate.clear();
}
@Override
public IterateOnlySetView<K> keySet()
{
return new IterateOnlySetView<K>()
{
@Override
public Iterator<K> iterator()
{
return delegate.keySet().stream().map(Equivalence.Wrapper::get).iterator();
}
};
}
@Override
public IterateOnlyCollectionView<V> values()
{
return new IterateOnlyCollectionView<V>()
{
@Override
public Iterator<V> iterator()
{
return Iterators.unmodifiableIterator(delegate.values().iterator());
}
};
}
@Override
public IterateOnlySetView<Entry<K, V>> entrySet()
{
return new IterateOnlySetView<Entry<K, V>>()
{
@Override
public Iterator<Entry<K, V>> iterator()
{
return delegate.entrySet().stream().map(e -> {
K key = e.getKey().get();
return (Entry<K, V>) new AbstractMap.SimpleEntry<>(key, e.getValue());
}).iterator();
}
};
}
public abstract class IterateOnlySetView<E>
extends IterateOnlyCollectionView<E>
implements Set<E>
{
private IterateOnlySetView() {}
}
public abstract class IterateOnlyCollectionView<E>
implements Collection<E>
{
private IterateOnlyCollectionView() {}
@Override
public int size()
{
return IdentityLinkedHashMap.this.size();
}
@Override
public boolean isEmpty()
{
return size() == 0;
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean contains(Object item)
{
// should use identity-based comparison whenever map's keys or values are compared
throw new UnsupportedOperationException();
}
@Override
public Object[] toArray()
{
return Iterators.toArray(iterator(), Object.class);
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public <T> T[] toArray(T[] array)
{
throw new UnsupportedOperationException();
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean add(E item)
{
throw new UnsupportedOperationException();
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean remove(Object item)
{
throw new UnsupportedOperationException();
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean containsAll(Collection<?> other)
{
throw new UnsupportedOperationException();
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean addAll(Collection<? extends E> other)
{
throw new UnsupportedOperationException();
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean retainAll(Collection<?> other)
{
throw new UnsupportedOperationException();
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean removeAll(Collection<?> other)
{
throw new UnsupportedOperationException();
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public void clear()
{
throw new UnsupportedOperationException();
}
@Override
public String toString()
{
return stream()
.map(String::valueOf)
.collect(joining(", ", "[", "]"));
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public int hashCode()
{
throw new UnsupportedOperationException();
}
/**
* @deprecated Unsupported operation.
*/
@Deprecated
@Override
public boolean equals(Object obj)
{
throw new UnsupportedOperationException();
}
}
}