477 lines
13 KiB
Java
477 lines
13 KiB
Java
package org.apache.commons.collections;
|
|
|
|
import java.io.Externalizable;
|
|
import java.io.IOException;
|
|
import java.io.ObjectInput;
|
|
import java.io.ObjectOutput;
|
|
import java.util.AbstractCollection;
|
|
import java.util.AbstractSet;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.ConcurrentModificationException;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.Set;
|
|
|
|
public class SequencedHashMap implements Map, Cloneable, Externalizable {
|
|
private Entry sentinel = createSentinel();
|
|
|
|
private HashMap entries = new HashMap();
|
|
|
|
private transient long modCount = 0L;
|
|
|
|
private static final int KEY = 0;
|
|
|
|
private static final int VALUE = 1;
|
|
|
|
private static final int ENTRY = 2;
|
|
|
|
private static final int REMOVED_MASK = -2147483648;
|
|
|
|
private static final long serialVersionUID = 3380552487888102930L;
|
|
|
|
public SequencedHashMap() {}
|
|
|
|
public SequencedHashMap(int paramInt) {}
|
|
|
|
public SequencedHashMap(int paramInt, float paramFloat) {}
|
|
|
|
public SequencedHashMap(Map paramMap) {
|
|
this();
|
|
putAll(paramMap);
|
|
}
|
|
|
|
public void clear() {
|
|
this.modCount++;
|
|
this.entries.clear();
|
|
this.sentinel.next = this.sentinel;
|
|
this.sentinel.prev = this.sentinel;
|
|
}
|
|
|
|
public Object clone() throws CloneNotSupportedException {
|
|
SequencedHashMap sequencedHashMap = (SequencedHashMap)super.clone();
|
|
sequencedHashMap.sentinel = createSentinel();
|
|
sequencedHashMap.entries = new HashMap();
|
|
sequencedHashMap.putAll(this);
|
|
return sequencedHashMap;
|
|
}
|
|
|
|
public boolean containsKey(Object paramObject) {
|
|
return this.entries.containsKey(paramObject);
|
|
}
|
|
|
|
public boolean containsValue(Object paramObject) {
|
|
if (paramObject == null) {
|
|
for (Entry entry = this.sentinel.next; entry != this.sentinel; entry = entry.next) {
|
|
if (entry.getValue() == null)
|
|
return true;
|
|
}
|
|
} else {
|
|
for (Entry entry = this.sentinel.next; entry != this.sentinel; entry = entry.next) {
|
|
if (paramObject.equals(entry.getValue()))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static final Entry createSentinel() {
|
|
Entry entry = new Entry(null, null);
|
|
entry.prev = entry;
|
|
entry.next = entry;
|
|
return entry;
|
|
}
|
|
|
|
public Set entrySet() {
|
|
return new AbstractSet(this) {
|
|
private final SequencedHashMap this$0;
|
|
|
|
public void clear() {
|
|
this.this$0.clear();
|
|
}
|
|
|
|
public boolean contains(Object param1Object) {
|
|
return !(findEntry(param1Object) == null);
|
|
}
|
|
|
|
private SequencedHashMap.Entry findEntry(Object param1Object) {
|
|
if (param1Object == null)
|
|
return null;
|
|
if (!(param1Object instanceof Map.Entry))
|
|
return null;
|
|
Map.Entry entry = (Map.Entry)param1Object;
|
|
SequencedHashMap.Entry entry1 = (SequencedHashMap.Entry)this.this$0.entries.get(entry.getKey());
|
|
return (entry1 != null && entry1.equals(entry)) ? entry1 : null;
|
|
}
|
|
|
|
public boolean isEmpty() {
|
|
return this.this$0.isEmpty();
|
|
}
|
|
|
|
public Iterator iterator() {
|
|
return new SequencedHashMap.OrderedIterator(this.this$0, 2);
|
|
}
|
|
|
|
public boolean remove(Object param1Object) {
|
|
SequencedHashMap.Entry entry = findEntry(param1Object);
|
|
return (entry == null) ? false : (!(this.this$0.removeImpl(entry.getKey()) == null));
|
|
}
|
|
|
|
public int size() {
|
|
return this.this$0.size();
|
|
}
|
|
};
|
|
}
|
|
|
|
public boolean equals(Object paramObject) {
|
|
return (paramObject == null) ? false : ((paramObject == this) ? true : (!(paramObject instanceof Map) ? false : entrySet().equals(((Map)paramObject).entrySet())));
|
|
}
|
|
|
|
public Object get(int paramInt) {
|
|
return getEntry(paramInt).getKey();
|
|
}
|
|
|
|
public Object get(Object paramObject) {
|
|
Entry entry = (Entry)this.entries.get(paramObject);
|
|
return (entry == null) ? null : entry.getValue();
|
|
}
|
|
|
|
private Map.Entry getEntry(int paramInt) {
|
|
Entry entry = this.sentinel;
|
|
if (paramInt < 0)
|
|
throw new ArrayIndexOutOfBoundsException(String.valueOf(paramInt) + " < 0");
|
|
byte b = -1;
|
|
while (b < paramInt - 1 && entry.next != this.sentinel) {
|
|
b++;
|
|
entry = entry.next;
|
|
}
|
|
if (entry.next == this.sentinel)
|
|
throw new ArrayIndexOutOfBoundsException(String.valueOf(paramInt) + " >= " + (b + 1));
|
|
return entry.next;
|
|
}
|
|
|
|
public Map.Entry getFirst() {
|
|
return isEmpty() ? null : this.sentinel.next;
|
|
}
|
|
|
|
public Object getFirstKey() {
|
|
return this.sentinel.next.getKey();
|
|
}
|
|
|
|
public Object getFirstValue() {
|
|
return this.sentinel.next.getValue();
|
|
}
|
|
|
|
public Map.Entry getLast() {
|
|
return isEmpty() ? null : this.sentinel.prev;
|
|
}
|
|
|
|
public Object getLastKey() {
|
|
return this.sentinel.prev.getKey();
|
|
}
|
|
|
|
public Object getLastValue() {
|
|
return this.sentinel.prev.getValue();
|
|
}
|
|
|
|
public Object getValue(int paramInt) {
|
|
return getEntry(paramInt).getValue();
|
|
}
|
|
|
|
public int hashCode() {
|
|
return entrySet().hashCode();
|
|
}
|
|
|
|
public int indexOf(Object paramObject) {
|
|
Entry entry = (Entry)this.entries.get(paramObject);
|
|
byte b = 0;
|
|
while (entry.prev != this.sentinel) {
|
|
b++;
|
|
entry = entry.prev;
|
|
}
|
|
return b;
|
|
}
|
|
|
|
private void insertEntry(Entry paramEntry) {
|
|
paramEntry.next = this.sentinel;
|
|
paramEntry.prev = this.sentinel.prev;
|
|
this.sentinel.prev.next = paramEntry;
|
|
this.sentinel.prev = paramEntry;
|
|
}
|
|
|
|
public boolean isEmpty() {
|
|
return !(this.sentinel.next != this.sentinel);
|
|
}
|
|
|
|
public Iterator iterator() {
|
|
return keySet().iterator();
|
|
}
|
|
|
|
public Set keySet() {
|
|
return new AbstractSet(this) {
|
|
private final SequencedHashMap this$0;
|
|
|
|
public void clear() {
|
|
this.this$0.clear();
|
|
}
|
|
|
|
public boolean contains(Object param1Object) {
|
|
return this.this$0.containsKey(param1Object);
|
|
}
|
|
|
|
public boolean isEmpty() {
|
|
return this.this$0.isEmpty();
|
|
}
|
|
|
|
public Iterator iterator() {
|
|
return new SequencedHashMap.OrderedIterator(this.this$0, 0);
|
|
}
|
|
|
|
public boolean remove(Object param1Object) {
|
|
SequencedHashMap.Entry entry = this.this$0.removeImpl(param1Object);
|
|
return !(entry == null);
|
|
}
|
|
|
|
public int size() {
|
|
return this.this$0.size();
|
|
}
|
|
};
|
|
}
|
|
|
|
public int lastIndexOf(Object paramObject) {
|
|
return indexOf(paramObject);
|
|
}
|
|
|
|
public Object put(Object paramObject1, Object paramObject2) {
|
|
this.modCount++;
|
|
Object object = null;
|
|
Entry entry = (Entry)this.entries.get(paramObject1);
|
|
if (entry != null) {
|
|
removeEntry(entry);
|
|
object = entry.setValue(paramObject2);
|
|
} else {
|
|
entry = new Entry(paramObject1, paramObject2);
|
|
this.entries.put(paramObject1, entry);
|
|
}
|
|
insertEntry(entry);
|
|
return object;
|
|
}
|
|
|
|
public void putAll(Map paramMap) {
|
|
for (Map.Entry entry : paramMap.entrySet())
|
|
put(entry.getKey(), entry.getValue());
|
|
}
|
|
|
|
public void readExternal(ObjectInput paramObjectInput) throws IOException, ClassNotFoundException {
|
|
int i = paramObjectInput.readInt();
|
|
for (byte b = 0; b < i; b++) {
|
|
Object object1 = paramObjectInput.readObject();
|
|
Object object2 = paramObjectInput.readObject();
|
|
put(object1, object2);
|
|
}
|
|
}
|
|
|
|
public Object remove(int paramInt) {
|
|
return remove(get(paramInt));
|
|
}
|
|
|
|
public Object remove(Object paramObject) {
|
|
Entry entry = removeImpl(paramObject);
|
|
return (entry == null) ? null : entry.getValue();
|
|
}
|
|
|
|
private void removeEntry(Entry paramEntry) {
|
|
paramEntry.next.prev = paramEntry.prev;
|
|
paramEntry.prev.next = paramEntry.next;
|
|
}
|
|
|
|
private Entry removeImpl(Object paramObject) {
|
|
Entry entry = (Entry)this.entries.remove(paramObject);
|
|
if (entry == null)
|
|
return null;
|
|
this.modCount++;
|
|
removeEntry(entry);
|
|
return entry;
|
|
}
|
|
|
|
public List sequence() {
|
|
ArrayList arrayList = new ArrayList(size());
|
|
Iterator iterator = keySet().iterator();
|
|
while (iterator.hasNext())
|
|
arrayList.add(iterator.next());
|
|
return Collections.unmodifiableList(arrayList);
|
|
}
|
|
|
|
public int size() {
|
|
return this.entries.size();
|
|
}
|
|
|
|
public String toString() {
|
|
StringBuffer stringBuffer = new StringBuffer();
|
|
stringBuffer.append('[');
|
|
for (Entry entry = this.sentinel.next; entry != this.sentinel; entry = entry.next) {
|
|
stringBuffer.append(entry.getKey());
|
|
stringBuffer.append('=');
|
|
stringBuffer.append(entry.getValue());
|
|
if (entry.next != this.sentinel)
|
|
stringBuffer.append(',');
|
|
}
|
|
stringBuffer.append(']');
|
|
return stringBuffer.toString();
|
|
}
|
|
|
|
public Collection values() {
|
|
return new AbstractCollection(this) {
|
|
private final SequencedHashMap this$0;
|
|
|
|
public void clear() {
|
|
this.this$0.clear();
|
|
}
|
|
|
|
public boolean contains(Object param1Object) {
|
|
return this.this$0.containsValue(param1Object);
|
|
}
|
|
|
|
public boolean isEmpty() {
|
|
return this.this$0.isEmpty();
|
|
}
|
|
|
|
public Iterator iterator() {
|
|
return new SequencedHashMap.OrderedIterator(this.this$0, 1);
|
|
}
|
|
|
|
public boolean remove(Object param1Object) {
|
|
if (param1Object == null) {
|
|
for (SequencedHashMap.Entry entry = this.this$0.sentinel.next; entry != this.this$0.sentinel; entry = entry.next) {
|
|
if (entry.getValue() == null) {
|
|
this.this$0.removeImpl(entry.getKey());
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
for (SequencedHashMap.Entry entry = this.this$0.sentinel.next; entry != this.this$0.sentinel; entry = entry.next) {
|
|
if (param1Object.equals(entry.getValue())) {
|
|
this.this$0.removeImpl(entry.getKey());
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public int size() {
|
|
return this.this$0.size();
|
|
}
|
|
};
|
|
}
|
|
|
|
public void writeExternal(ObjectOutput paramObjectOutput) throws IOException {
|
|
paramObjectOutput.writeInt(size());
|
|
for (Entry entry = this.sentinel.next; entry != this.sentinel; entry = entry.next) {
|
|
paramObjectOutput.writeObject(entry.getKey());
|
|
paramObjectOutput.writeObject(entry.getValue());
|
|
}
|
|
}
|
|
|
|
private static class Entry implements Map.Entry {
|
|
private final Object key;
|
|
|
|
private Object value;
|
|
|
|
Entry next = null;
|
|
|
|
Entry prev = null;
|
|
|
|
public Entry(Object param1Object1, Object param1Object2) {
|
|
this.key = param1Object1;
|
|
this.value = param1Object2;
|
|
}
|
|
|
|
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;
|
|
return !(!((getKey() == null) ? (entry.getKey() == null) : getKey().equals(entry.getKey())) || !((getValue() == null) ? (entry.getValue() == null) : getValue().equals(entry.getValue())));
|
|
}
|
|
|
|
public Object getKey() {
|
|
return this.key;
|
|
}
|
|
|
|
public Object getValue() {
|
|
return this.value;
|
|
}
|
|
|
|
public int hashCode() {
|
|
return ((getKey() == null) ? 0 : getKey().hashCode()) ^ ((getValue() == null) ? 0 : getValue().hashCode());
|
|
}
|
|
|
|
public Object setValue(Object param1Object) {
|
|
Object object = this.value;
|
|
this.value = param1Object;
|
|
return object;
|
|
}
|
|
|
|
public String toString() {
|
|
return "[" + getKey() + "=" + getValue() + "]";
|
|
}
|
|
}
|
|
|
|
private class OrderedIterator implements Iterator {
|
|
private final SequencedHashMap this$0;
|
|
|
|
private int returnType;
|
|
|
|
private SequencedHashMap.Entry pos;
|
|
|
|
private transient long expectedModCount;
|
|
|
|
public OrderedIterator(SequencedHashMap this$0, int param1Int) {
|
|
this.this$0 = this$0;
|
|
this.pos = this.this$0.sentinel;
|
|
this.expectedModCount = this.this$0.modCount;
|
|
this.returnType = param1Int | Integer.MIN_VALUE;
|
|
}
|
|
|
|
public boolean hasNext() {
|
|
return !(this.pos.next == this.this$0.sentinel);
|
|
}
|
|
|
|
public Object next() {
|
|
if (this.this$0.modCount != this.expectedModCount)
|
|
throw new ConcurrentModificationException();
|
|
if (this.pos.next == this.this$0.sentinel)
|
|
throw new NoSuchElementException();
|
|
this.returnType &= Integer.MAX_VALUE;
|
|
this.pos = this.pos.next;
|
|
switch (this.returnType) {
|
|
case 0:
|
|
return this.pos.getKey();
|
|
case 1:
|
|
return this.pos.getValue();
|
|
case 2:
|
|
return this.pos;
|
|
}
|
|
throw new Error("bad iterator type: " + this.returnType);
|
|
}
|
|
|
|
public void remove() {
|
|
if ((this.returnType & Integer.MIN_VALUE) != 0)
|
|
throw new IllegalStateException("remove() must follow next()");
|
|
if (this.this$0.modCount != this.expectedModCount)
|
|
throw new ConcurrentModificationException();
|
|
this.this$0.removeImpl(this.pos.getKey());
|
|
this.expectedModCount++;
|
|
this.returnType |= Integer.MIN_VALUE;
|
|
}
|
|
}
|
|
}
|