package org.apache.commons.collections; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; public class ReferenceMap extends AbstractMap { private static final long serialVersionUID = -3370601314380922368L; public static final int HARD = 0; public static final int SOFT = 1; public static final int WEAK = 2; private int keyType; private int valueType; private float loadFactor; private transient ReferenceQueue queue = new ReferenceQueue(); private transient Entry[] table; private transient int size; private transient int threshold; private volatile transient int modCount; private transient Set keySet; private transient Set entrySet; private transient Collection values; public ReferenceMap() { this(0, 1); } public ReferenceMap(int paramInt1, int paramInt2) { this(paramInt1, paramInt2, 16, 0.75F); } public ReferenceMap(int paramInt1, int paramInt2, int paramInt3, float paramFloat) { verify("keyType", paramInt1); verify("valueType", paramInt2); if (paramInt3 <= 0) throw new IllegalArgumentException("capacity must be positive"); if (paramFloat <= 0.0F || paramFloat >= 1.0F) throw new IllegalArgumentException("Load factor must be greater than 0 and less than 1."); this.keyType = paramInt1; this.valueType = paramInt2; int i; for (i = 1; i < paramInt3; i *= 2); this.table = new Entry[i]; this.loadFactor = paramFloat; this.threshold = (int)(i * paramFloat); } public void clear() { Arrays.fill((Object[])this.table, (Object)null); this.size = 0; do { } while (this.queue.poll() != null); } public boolean containsKey(Object paramObject) { purge(); Entry entry = getEntry(paramObject); return (entry == null) ? false : (!(entry.getValue() == null)); } public Set entrySet() { if (this.entrySet != null) return this.entrySet; this.entrySet = new AbstractSet(this) { private final ReferenceMap this$0; public void clear() { this.this$0.clear(); } public boolean contains(Object param1Object) { if (param1Object == null) return false; if (!(param1Object instanceof Map.Entry)) return false; Map.Entry entry = (Map.Entry)param1Object; ReferenceMap.Entry entry1 = this.this$0.getEntry(entry.getKey()); return !(entry1 == null || !entry.equals(entry1)); } public Iterator iterator() { return new ReferenceMap.EntryIterator(this.this$0); } public boolean remove(Object param1Object) { boolean bool = contains(param1Object); if (bool) { Map.Entry entry = (Map.Entry)param1Object; this.this$0.remove(entry.getKey()); } return bool; } public int size() { return this.this$0.size(); } public Object[] toArray() { return toArray(new Object[0]); } public Object[] toArray(Object[] param1ArrayOfObject) { ArrayList arrayList = new ArrayList(); for (ReferenceMap.Entry entry : this) arrayList.add(new DefaultMapEntry(entry.getKey(), entry.getValue())); return arrayList.toArray(param1ArrayOfObject); } }; return this.entrySet; } public Object get(Object paramObject) { purge(); Entry entry = getEntry(paramObject); return (entry == null) ? null : entry.getValue(); } private Entry getEntry(Object paramObject) { if (paramObject == null) return null; int i = paramObject.hashCode(); int j = indexFor(i); for (Entry entry = this.table[j]; entry != null; entry = entry.next) { if (entry.hash == i && paramObject.equals(entry.getKey())) return entry; } return null; } private int indexFor(int paramInt) { paramInt += paramInt << 15 ^ 0xFFFFFFFF; paramInt ^= paramInt >>> 10; paramInt += paramInt << 3; paramInt ^= paramInt >>> 6; paramInt += paramInt << 11 ^ 0xFFFFFFFF; paramInt ^= paramInt >>> 16; return paramInt & this.table.length - 1; } public boolean isEmpty() { purge(); return !(this.size != 0); } public Set keySet() { if (this.keySet != null) return this.keySet; this.keySet = new AbstractSet(this) { private final ReferenceMap this$0; public void clear() { this.this$0.clear(); } public boolean contains(Object param1Object) { return this.this$0.containsKey(param1Object); } public Iterator iterator() { return new ReferenceMap.KeyIterator(this.this$0); } public boolean remove(Object param1Object) { Object object = this.this$0.remove(param1Object); return !(object == null); } public int size() { return this.this$0.size; } }; return this.keySet; } private void purge() { for (Reference reference = this.queue.poll(); reference != null; reference = this.queue.poll()) purge(reference); } private void purge(Reference paramReference) { int i = paramReference.hashCode(); int j = indexFor(i); Entry entry1 = null; for (Entry entry2 = this.table[j]; entry2 != null; entry2 = entry2.next) { if (entry2.purge(paramReference)) { if (entry1 == null) { this.table[j] = entry2.next; } else { entry1.next = entry2.next; } this.size--; return; } entry1 = entry2; } } public Object put(Object paramObject1, Object paramObject2) { if (paramObject1 == null) throw new NullPointerException("null keys not allowed"); if (paramObject2 == null) throw new NullPointerException("null values not allowed"); purge(); if (this.size + 1 > this.threshold) resize(); int i = paramObject1.hashCode(); int j = indexFor(i); for (Entry entry = this.table[j]; entry != null; entry = entry.next) { if (i == entry.hash && paramObject1.equals(entry.getKey())) { Object object = entry.getValue(); entry.setValue(paramObject2); return object; } } this.size++; this.modCount++; paramObject1 = toReference(this.keyType, paramObject1, i); paramObject2 = toReference(this.valueType, paramObject2, i); this.table[j] = new Entry(this, paramObject1, i, paramObject2, this.table[j]); return null; } private void readObject(ObjectInputStream paramObjectInputStream) throws IOException, ClassNotFoundException { paramObjectInputStream.defaultReadObject(); this.table = new Entry[paramObjectInputStream.readInt()]; this.threshold = (int)(this.table.length * this.loadFactor); this.queue = new ReferenceQueue(); for (Object object = paramObjectInputStream.readObject(); object != null; object = paramObjectInputStream.readObject()) { Object object1 = paramObjectInputStream.readObject(); put(object, object1); } } public Object remove(Object paramObject) { if (paramObject == null) return null; purge(); int i = paramObject.hashCode(); int j = indexFor(i); Entry entry1 = null; for (Entry entry2 = this.table[j]; entry2 != null; entry2 = entry2.next) { if (i == entry2.hash && paramObject.equals(entry2.getKey())) { if (entry1 == null) { this.table[j] = entry2.next; } else { entry1.next = entry2.next; } this.size--; this.modCount++; return entry2.getValue(); } entry1 = entry2; } return null; } private void resize() { Entry[] arrayOfEntry = this.table; this.table = new Entry[arrayOfEntry.length * 2]; for (byte b = 0; b < arrayOfEntry.length; b++) { Entry entry = arrayOfEntry[b]; while (entry != null) { Entry entry1 = entry; entry = entry.next; int i = indexFor(entry1.hash); entry1.next = this.table[i]; this.table[i] = entry1; } arrayOfEntry[b] = null; } this.threshold = (int)(this.table.length * this.loadFactor); } public int size() { purge(); return this.size; } private Object toReference(int paramInt1, Object paramObject, int paramInt2) { switch (paramInt1) { case 0: return paramObject; case 1: return new SoftRef(paramInt2, paramObject, this.queue); case 2: return new WeakRef(paramInt2, paramObject, this.queue); } throw new Error(); } public Collection values() { if (this.values != null) return this.values; this.values = new AbstractCollection(this) { private final ReferenceMap this$0; public void clear() { this.this$0.clear(); } public Iterator iterator() { return new ReferenceMap.ValueIterator(this.this$0); } public int size() { return this.this$0.size; } }; return this.values; } private static void verify(String paramString, int paramInt) { if (paramInt < 0 || paramInt > 2) throw new IllegalArgumentException(String.valueOf(paramString) + " must be HARD, SOFT, WEAK."); } private void writeObject(ObjectOutputStream paramObjectOutputStream) throws IOException { paramObjectOutputStream.defaultWriteObject(); paramObjectOutputStream.writeInt(this.table.length); for (Map.Entry entry : entrySet()) { paramObjectOutputStream.writeObject(entry.getKey()); paramObjectOutputStream.writeObject(entry.getValue()); } paramObjectOutputStream.writeObject(null); } private class Entry implements Map.Entry { private final ReferenceMap this$0; Object key; Object value; int hash; Entry next; public Entry(ReferenceMap this$0, Object param1Object1, int param1Int, Object param1Object2, Entry param1Entry) { this.this$0 = this$0; this.key = param1Object1; this.hash = param1Int; this.value = param1Object2; this.next = param1Entry; } public boolean equals(Object param1Object) { if (param1Object == null) return false; if (param1Object == this) return true; if (!(param1Object instanceof Map.Entry)) return false; Map.Entry entry = (Map.Entry)param1Object; Object object1 = entry.getKey(); Object object2 = entry.getValue(); return (object1 == null || object2 == null) ? false : (!(!object1.equals(getKey()) || !object2.equals(getValue()))); } public Object getKey() { return (this.this$0.keyType > 0) ? ((Reference)this.key).get() : this.key; } public Object getValue() { return (this.this$0.valueType > 0) ? ((Reference)this.value).get() : this.value; } public int hashCode() { Object object = getValue(); return this.hash ^ ((object == null) ? 0 : object.hashCode()); } boolean purge(Reference param1Reference) { boolean bool = (this.this$0.keyType <= 0 || this.key != param1Reference) ? false : true; bool = (!bool && (this.this$0.valueType <= 0 || this.value != param1Reference)) ? false : true; if (bool) { if (this.this$0.keyType > 0) ((Reference)this.key).clear(); if (this.this$0.valueType > 0) ((Reference)this.value).clear(); } return bool; } public Object setValue(Object param1Object) { Object object = getValue(); if (this.this$0.valueType > 0) ((Reference)this.value).clear(); this.value = this.this$0.toReference(this.this$0.valueType, param1Object, this.hash); return object; } public String toString() { return String.valueOf(String.valueOf(getKey())) + "=" + getValue(); } } private class EntryIterator implements Iterator { private final ReferenceMap this$0; int index; ReferenceMap.Entry entry; ReferenceMap.Entry previous; Object nextKey; Object nextValue; Object currentKey; Object currentValue; int expectedModCount; public EntryIterator(ReferenceMap this$0) { this.this$0 = this$0; this.index = (this$0.size() != 0) ? this$0.table.length : 0; this.expectedModCount = this$0.modCount; } private void checkMod() { if (this.this$0.modCount != this.expectedModCount) throw new ConcurrentModificationException(); } public boolean hasNext() { checkMod(); while (nextNull()) { ReferenceMap.Entry entry = this.entry; int i = this.index; while (entry == null && i > 0) entry = this.this$0.table[--i]; this.entry = entry; this.index = i; if (entry == null) { this.currentKey = null; this.currentValue = null; return false; } this.nextKey = entry.getKey(); this.nextValue = entry.getValue(); if (nextNull()) this.entry = this.entry.next; } return true; } public Object next() { return nextEntry(); } protected ReferenceMap.Entry nextEntry() { checkMod(); if (nextNull() && !hasNext()) throw new NoSuchElementException(); this.previous = this.entry; this.entry = this.entry.next; this.currentKey = this.nextKey; this.currentValue = this.nextValue; this.nextKey = null; this.nextValue = null; return this.previous; } private boolean nextNull() { return !(this.nextKey != null && this.nextValue != null); } public void remove() { checkMod(); if (this.previous == null) throw new IllegalStateException(); this.this$0.remove(this.currentKey); this.previous = null; this.currentKey = null; this.currentValue = null; this.expectedModCount = this.this$0.modCount; } } private class ValueIterator extends EntryIterator { private final ReferenceMap this$0; ValueIterator(ReferenceMap this$0) { super(this$0); this.this$0 = this$0; } public Object next() { return nextEntry().getValue(); } } private class KeyIterator extends EntryIterator { private final ReferenceMap this$0; KeyIterator(ReferenceMap this$0) { super(this$0); this.this$0 = this$0; } public Object next() { return nextEntry().getKey(); } } private static class SoftRef extends SoftReference { private int hash; public SoftRef(int param1Int, Object param1Object, ReferenceQueue param1ReferenceQueue) { super((T)param1Object, param1ReferenceQueue); this.hash = param1Int; } public int hashCode() { return this.hash; } } private static class WeakRef extends WeakReference { private int hash; public WeakRef(int param1Int, Object param1Object, ReferenceQueue param1ReferenceQueue) { super((T)param1Object, param1ReferenceQueue); this.hash = param1Int; } public int hashCode() { return this.hash; } } }