/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.*;
// A weak key reference hash map that uses System.identityHashCode() and "=="
// instead of hashCode() and equals(Object)
class WeakIdentityHashMap<K, V> implements Map<K, V> {
private final Map<WeakKey<K>, V> map;
private final transient ReferenceQueue<K> queue = new ReferenceQueue<K>();
Constructs a new, empty identity hash map with a default initial
size (16).
/**
* Constructs a new, empty identity hash map with a default initial
* size (16).
*/
public WeakIdentityHashMap() {
map = new HashMap<>(16);
}
Constructs a new, empty identity map with the specified initial size.
/**
* Constructs a new, empty identity map with the specified initial size.
*/
public WeakIdentityHashMap(int initialSize) {
map = new HashMap<>(initialSize);
}
private Map<WeakKey<K>, V> getMap() {
for(Reference<? extends K> ref; (ref = this.queue.poll()) != null;) {
map.remove(ref);
}
return map;
}
@Override
public int size() {
return getMap().size();
}
@Override
public boolean isEmpty() {
return getMap().isEmpty();
}
@Override
public boolean containsKey(Object key) {
return getMap().containsKey(new WeakKey<>(key, null));
}
@Override
public boolean containsValue(Object value) {
return getMap().containsValue(value);
}
@Override
public V get(Object key) {
return getMap().get(new WeakKey<>(key, null));
}
@Override
public V put(K key, V value) {
return getMap().put(new WeakKey<K>(key, queue), value);
}
@Override
public V remove(Object key) {
return getMap().remove(new WeakKey<>(key, null));
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public void clear() {
getMap().clear();
}
@Override
public Set<K> keySet() {
return new AbstractSet<K>() {
@Override
public Iterator<K> iterator() {
return new Iterator<K>() {
private K next;
Iterator<WeakKey<K>> iterator = getMap().keySet().iterator();
@Override
public boolean hasNext() {
while (iterator.hasNext()) {
if ((next = iterator.next().get()) != null) {
return true;
}
}
return false;
}
@Override
public K next() {
if(next == null && !hasNext()) {
throw new NoSuchElementException();
}
K ret = next;
next = null;
return ret;
}
};
}
@Override
public int size() {
return getMap().keySet().size();
}
};
}
@Override
public Collection<V> values() {
return getMap().values();
}
@Override
public Set<Entry<K, V>> entrySet() {
return new AbstractSet<Entry<K, V>>() {
@Override
public Iterator<Entry<K, V>> iterator() {
final Iterator<Entry<WeakKey<K>, V>> iterator = getMap().entrySet().iterator();
return new Iterator<Entry<K, V>>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Entry<K, V> next() {
return new Entry<K, V>() {
Entry<WeakKey<K>, V> entry = iterator.next();
@Override
public K getKey() {
return entry.getKey().get();
}
@Override
public V getValue() {
return entry.getValue();
}
@Override
public V setValue(V value) {
return null;
}
};
}
};
}
@Override
public int size() {
return getMap().entrySet().size();
}
};
}
private static class WeakKey<K> extends WeakReference<K> {
private final int hash;
WeakKey(K key, ReferenceQueue <K> q) {
super(key, q);
hash = System.identityHashCode(key);
}
@Override
public boolean equals(Object o) {
if(this == o) {
return true;
} else if( o instanceof WeakKey ) {
return get() == ((WeakKey)o).get();
} else {
return false;
}
}
@Override
public int hashCode() {
return hash;
}
}
}