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;
public final class IdentityMap<K,V> implements Map<K,V> {
private final Map<IdentityKey<K>,V> map;
@SuppressWarnings( {"unchecked"})
private transient Entry<IdentityKey<K>,V>[] entryArray = new Entry[0];
private transient boolean dirty;
public static <K,V> IdentityMap<K,V> instantiateSequenced(int size) {
return new IdentityMap<K,V>( new LinkedHashMap<IdentityKey<K>,V>( size ) );
}
private IdentityMap(Map<IdentityKey<K>,V> underlyingMap) {
map = underlyingMap;
dirty = true;
}
public static <K,V> Map.Entry<K,V>[] concurrentEntries(Map<K,V> map) {
return ( (IdentityMap<K,V>) map ).entryArray();
}
public Iterator<K> keyIterator() {
return new KeyIterator<K>( 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) {
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) {
dirty = true;
return map.put( new IdentityKey<K>(key), value );
}
@Override
@SuppressWarnings( {"unchecked"})
public V remove(Object key) {
dirty = true;
return map.remove( new IdentityKey(key) );
}
@Override
public void putAll(Map<? extends K, ? extends V> otherMap) {
for ( Entry<? extends K, ? extends V> entry : otherMap.entrySet() ) {
put( entry.getKey(), entry.getValue() );
}
}
@Override
public void clear() {
dirty = true;
entryArray = null;
map.clear();
}
@Override
public Set<K> keySet() {
throw new UnsupportedOperationException();
}
@Override
public Collection<V> values() {
return map.values();
}
@Override
public Set<Entry<K,V>> entrySet() {
Set<Entry<K,V>> set = new HashSet<Entry<K,V>>( map.size() );
for ( Entry<IdentityKey<K>, V> entry : map.entrySet() ) {
set.add( new IdentityMapEntry<K,V>( entry.getKey().getRealKey(), entry.getValue() ) );
}
return set;
}
@SuppressWarnings( {"unchecked"})
public Map.Entry[] entryArray() {
if (dirty) {
entryArray = new Map.Entry[ map.size() ];
Iterator itr = map.entrySet().iterator();
int i=0;
while ( itr.hasNext() ) {
Map.Entry me = (Map.Entry) itr.next();
entryArray[i++] = new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() );
}
dirty = false;
}
return entryArray;
}
@Override
public String toString() {
return map.toString();
}
static final class KeyIterator<K> implements Iterator<K> {
private final Iterator<IdentityKey<K>> identityKeyIterator;
private KeyIterator(Iterator<IdentityKey<K>> iterator) {
identityKeyIterator = iterator;
}
public boolean hasNext() {
return identityKeyIterator.hasNext();
}
public K next() {
return identityKeyIterator.next().getRealKey();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
public static final class IdentityMapEntry<K,V> implements java.util.Map.Entry<K,V> {
private final K key;
private 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) {
V result = this.value;
this.value = value;
return result;
}
}
public static final class IdentityKey<K> implements Serializable {
private final K key;
private int hash;
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() {
if ( this.hash == 0 ) {
final int newHash = System.identityHashCode( key );
if ( newHash == 0 ) {
this.hash = -1;
return -1;
}
else {
this.hash = newHash;
return newHash;
}
}
return hash;
}
@Override
public String toString() {
return key.toString();
}
public K getRealKey() {
return key;
}
}
}