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; } } }