org.hibernate.internal.util.collections.IdentityMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
Hibernate's core ORM functionality
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.internal.util.collections;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
/**
* A Map where keys are compared by object identity,
* rather than equals().
*/
public final class IdentityMap implements Map {
private final LinkedHashMap,V> map;
@SuppressWarnings( {"unchecked"})
private transient Map.Entry,V>[] entryArray = null;
/**
* Return a new instance of this class, with iteration
* order defined as the order in which entries were added
*
* @param size The size of the map to create
* @return The map
*/
public static IdentityMap instantiateSequenced(int size) {
return new IdentityMap( new LinkedHashMap<>( size << 1, 0.6f ) );
}
/**
* Private ctor used in serialization.
*
* @param underlyingMap The delegate map.
*/
private IdentityMap(LinkedHashMap,V> underlyingMap) {
map = underlyingMap;
}
/**
* Return the map entries (as instances of Map.Entry in a collection that
* is safe from concurrent modification). ie. we may safely add new instances to
* the underlying Map during iteration of the entries().
*
* @param map The map of entries
* @return Collection
*/
public static Map.Entry[] concurrentEntries(Map map) {
return ( (IdentityMap) map ).entryArray();
}
public static void onEachKey(Map map, Consumer consumer) {
final IdentityMap identityMap = (IdentityMap) map;
identityMap.map.forEach( (kIdentityKey, v) -> consumer.accept( kIdentityKey.key ) );
}
/**
* Override Map{@link #forEach(BiConsumer)} to provide a more efficient implementation
* @param action the operation to apply to each element
*/
@Override
public void forEach(BiConsumer action) {
map.forEach( (k,v) -> action.accept( k.key, v ) );
}
public Iterator keyIterator() {
return new KeyIterator( map.keySet().iterator() );
}
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
@SuppressWarnings({ "unchecked" })
public boolean containsKey(Object key) {
return map.containsKey( new IdentityKey( key ) );
}
@Override
public boolean containsValue(Object val) {
throw new UnsupportedOperationException( "Avoid this operation: does not perform well" );
//return map.containsValue( val );
}
@Override
@SuppressWarnings( {"unchecked"})
public V get(Object key) {
return map.get( new IdentityKey( key ) );
}
@Override
public V put(K key, V value) {
this.entryArray = null;
return map.put( new IdentityKey( key ), value );
}
@Override
@SuppressWarnings( {"unchecked"})
public V remove(Object key) {
this.entryArray = null;
return map.remove( new IdentityKey( key ) );
}
@Override
public void putAll(Map otherMap) {
for ( Entry entry : otherMap.entrySet() ) {
put( entry.getKey(), entry.getValue() );
}
}
@Override
public void clear() {
entryArray = null;
map.clear();
}
@Override
public Set keySet() {
// would need an IdentitySet for this!
// (and we just don't use this method so it's ok)
throw new UnsupportedOperationException();
}
@Override
public Collection values() {
return map.values();
}
@Override
public Set> entrySet() {
Set> set = new HashSet>( map.size() );
for ( Entry, V> entry : map.entrySet() ) {
set.add( new IdentityMapEntry( entry.getKey().key, entry.getValue() ) );
}
return set;
}
@SuppressWarnings( {"unchecked"})
public Map.Entry[] entryArray() {
if ( entryArray == null ) {
entryArray = new Map.Entry[ map.size() ];
final Iterator, V>> itr = map.entrySet().iterator();
int i = 0;
while ( itr.hasNext() ) {
final Entry, V> me = itr.next();
entryArray[i++] = new IdentityMapEntry( me.getKey().key, me.getValue() );
}
}
return entryArray;
}
@Override
public String toString() {
return map.toString();
}
private static final class KeyIterator implements Iterator {
private final Iterator> identityKeyIterator;
private KeyIterator(Iterator> iterator) {
identityKeyIterator = iterator;
}
public boolean hasNext() {
return identityKeyIterator.hasNext();
}
public K next() {
return identityKeyIterator.next().key;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
private static final class IdentityMapEntry implements java.util.Map.Entry {
private final K key;
private final V value;
IdentityMapEntry(final K key, final V value) {
this.key=key;
this.value=value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public V setValue(final V value) {
throw new UnsupportedOperationException();
}
}
/**
* We need to base the identity on {@link System#identityHashCode(Object)}
*/
private static final class IdentityKey implements Serializable {
private final K key;
IdentityKey(K key) {
this.key = key;
}
@SuppressWarnings( {"EqualsWhichDoesntCheckParameterClass"})
@Override
public boolean equals(Object other) {
return other != null && key == ( (IdentityKey) other ).key;
}
@Override
public int hashCode() {
return System.identityHashCode( key );
}
@Override
public String toString() {
return key.toString();
}
}
}