diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index 47050105d8..146a4eb2e1 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -93,7 +93,7 @@ public class HashMap implements Map { array = newArray; } - private Cell find(Object key) { + protected Cell find(Object key) { if (array != null) { int index = helper.hash(key) & (array.length - 1); for (Cell c = array[index]; c != null; c = c.next()) { diff --git a/classpath/java/util/LinkedHashMap.java b/classpath/java/util/LinkedHashMap.java new file mode 100644 index 0000000000..ba5b9c09d9 --- /dev/null +++ b/classpath/java/util/LinkedHashMap.java @@ -0,0 +1,267 @@ +/* Copyright (c) 2008-2013, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util; + +public class LinkedHashMap extends HashMap { + private static class LinkedKey { + private final K key; + private LinkedKey previous, next; + + public LinkedKey(K key) { + this.key = key; + } + + public boolean equals(Object other) { + LinkedKey o = (LinkedKey) other; + return key.equals(o.key); + } + + public int hashCode() { + return key.hashCode(); + } + } + + private LinkedKey first, last; + private HashMap> lookup; + + public LinkedHashMap(int capacity) { + super(capacity); + lookup = new HashMap>(); + } + + public LinkedHashMap() { + this(0); + } + + public LinkedHashMap(Map map) { + this(map.size()); + putAll(map); + } + + public V put(K key, V value) { + if (!super.containsKey(key)) { + LinkedKey k = new LinkedKey(key); + if (first == null) { + first = k; + } else { + last.next = k; + k.previous = last; + } + last = k; + lookup.put(key, k); + } + return super.put(key, value); + } + + public V remove(Object key) { + LinkedKey linked = lookup.get(key); + if (linked == null) { + return null; + } + if (linked.previous == null) { + first = linked.next; + } else { + linked.previous.next = linked.next; + } + if (linked.next == null) { + last = linked.previous; + } else { + linked.next.previous = linked.previous; + } + return super.remove(key); + } + + public void clear() { + first = last = null; + super.clear(); + } + + public Set> entrySet() { + return new EntrySet(); + } + + public Set keySet() { + return new KeySet(); + } + + public Collection values() { + return new Values(); + } + + Iterator> iterator() { + return new MyIterator(); + } + + private class EntrySet extends AbstractSet> { + public int size() { + return LinkedHashMap.this.size(); + } + + public boolean isEmpty() { + return LinkedHashMap.this.isEmpty(); + } + + public boolean contains(Object o) { + return (o instanceof Entry) + && containsKey(((Entry)o).getKey()); + } + + public boolean add(Entry e) { + return put(e.getKey(), e.getValue()) != null; + } + + public boolean remove(Object o) { + return (o instanceof Entry) && remove((Entry)o); + } + + public boolean remove(Entry e) { + return LinkedHashMap.this.remove(e.getKey()) != null; + } + + public Object[] toArray() { + return toArray(new Object[size()]); + } + + public T[] toArray(T[] array) { + return Collections.toArray(this, array); + } + + public void clear() { + LinkedHashMap.this.clear(); + } + + public Iterator> iterator() { + return new MyIterator(); + } + } + + private class KeySet extends AbstractSet { + public int size() { + return LinkedHashMap.this.size(); + } + + public boolean isEmpty() { + return LinkedHashMap.this.isEmpty(); + } + + public boolean contains(Object key) { + return containsKey(key); + } + + public boolean add(K key) { + return put(key, null) != null; + } + + public boolean remove(Object key) { + return LinkedHashMap.this.remove(key) != null; + } + + public Object[] toArray() { + return toArray(new Object[size()]); + } + + public T[] toArray(T[] array) { + return Collections.toArray(this, array); + } + + public void clear() { + LinkedHashMap.this.clear(); + } + + public Iterator iterator() { + return new Collections.KeyIterator(new MyIterator()); + } + } + + private class Values implements Collection { + public int size() { + return LinkedHashMap.this.size(); + } + + public boolean isEmpty() { + return LinkedHashMap.this.isEmpty(); + } + + public boolean contains(Object value) { + return containsValue(value); + } + + public boolean containsAll(Collection c) { + if (c == null) { + throw new NullPointerException("collection is null"); + } + + Iterator it = c.iterator(); + while (it.hasNext()) { + if (! contains(it.next())) { + return false; + } + } + + return true; + } + + public boolean add(V value) { + throw new UnsupportedOperationException(); + } + + public boolean addAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + public boolean remove(Object value) { + throw new UnsupportedOperationException(); + } + + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public Object[] toArray() { + return toArray(new Object[size()]); + } + + public T[] toArray(T[] array) { + return Collections.toArray(this, array); + } + + public void clear() { + LinkedHashMap.this.clear(); + } + + public Iterator iterator() { + return new Collections.ValueIterator(new MyIterator()); + } + } + + private class MyIterator implements Iterator> { + private LinkedKey current = first; + + public Entry next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + Entry result = find(current.key); + current = current.next; + return result; + } + + public boolean hasNext() { + return current != null; + } + + public void remove() { + LinkedHashMap.this.remove(current == null ? + last.key : current.previous.key); + } + } +} +