From d327f6ba5a25ff85d70364f3b118975c39cc30a2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 25 Jul 2009 15:41:43 -0600 Subject: [PATCH] implement java.util.TreeMap --- classpath/java/util/Collections.java | 56 ++++++++ classpath/java/util/HashMap.java | 68 ++------- classpath/java/util/TreeMap.java | 197 +++++++++++++++++++++++++++ classpath/java/util/TreeSet.java | 30 +++- test/Tree.java | 56 ++++++++ 5 files changed, 341 insertions(+), 66 deletions(-) create mode 100644 classpath/java/util/TreeMap.java diff --git a/classpath/java/util/Collections.java b/classpath/java/util/Collections.java index 619a4c5c61..3b6ab87d87 100644 --- a/classpath/java/util/Collections.java +++ b/classpath/java/util/Collections.java @@ -64,6 +64,22 @@ public class Collections { return sb.toString(); } + static String toString(Map m) { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + for (Iterator it = m.entrySet().iterator(); it.hasNext();) { + Map.Entry e = it.next(); + sb.append(e.getKey()) + .append("=") + .append(e.getValue()); + if (it.hasNext()) { + sb.append(","); + } + } + sb.append("}"); + return sb.toString(); + } + static class IteratorEnumeration implements Enumeration { private final Iterator it; @@ -312,4 +328,44 @@ public class Collections { public static Set unmodifiableSet(Set hs) { return new UnmodifiableSet(hs); } + + static class KeyIterator implements Iterator { + private final Iterator> it; + + public KeyIterator(Iterator> it) { + this.it = it; + } + + public K next() { + return it.next().getKey(); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + } + + static class ValueIterator implements Iterator { + private final Iterator> it; + + public ValueIterator(Iterator> it) { + this.it = it; + } + + public V next() { + return it.next().getValue(); + } + + public boolean hasNext() { + return it.hasNext(); + } + + public void remove() { + it.remove(); + } + } } diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index dd6eb85f61..2bc46b5e9d 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -40,19 +40,7 @@ public class HashMap implements Map { } public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("{"); - for (Iterator> it = iterator(); it.hasNext();) { - Entry e = it.next(); - sb.append(e.getKey()) - .append("=") - .append(e.getValue()); - if (it.hasNext()) { - sb.append(","); - } - } - sb.append("}"); - return sb.toString(); + return Collections.toString(this); } private static int nextPowerOfTwo(int n) { @@ -324,7 +312,8 @@ public class HashMap implements Map { } public boolean contains(Object o) { - return (o instanceof Entry) ? containsKey(((Entry)o).getKey()) : false; + return (o instanceof Entry) + && containsKey(((Entry)o).getKey()); } public boolean add(Entry e) { @@ -337,9 +326,9 @@ public class HashMap implements Map { return change; } - public boolean remove(Object o) { - return (o instanceof Entry) ? remove((Entry)o) : false; - } + public boolean remove(Object o) { + return (o instanceof Entry) && remove((Entry)o); + } public boolean remove(Entry e) { return removeCell(e.getKey()) != null; @@ -394,11 +383,10 @@ public class HashMap implements Map { } public Iterator iterator() { - return new KeyIterator(new MyIterator()); + return new Collections.KeyIterator(new MyIterator()); } } - private class Values implements Collection { public int size() { return HashMap.this.size(); @@ -433,7 +421,7 @@ public class HashMap implements Map { } public Iterator iterator() { - return new ValueIterator(new MyIterator()); + return new Collections.ValueIterator(new MyIterator()); } } @@ -495,44 +483,4 @@ public class HashMap implements Map { } } } - - private static class KeyIterator implements Iterator { - private final Iterator> it; - - public KeyIterator(Iterator> it) { - this.it = it; - } - - public K next() { - return it.next().getKey(); - } - - public boolean hasNext() { - return it.hasNext(); - } - - public void remove() { - it.remove(); - } - } - - private static class ValueIterator implements Iterator { - private final Iterator> it; - - public ValueIterator(Iterator> it) { - this.it = it; - } - - public V next() { - return it.next().getValue(); - } - - public boolean hasNext() { - return it.hasNext(); - } - - public void remove() { - it.remove(); - } - } } diff --git a/classpath/java/util/TreeMap.java b/classpath/java/util/TreeMap.java new file mode 100644 index 0000000000..d08bd4958d --- /dev/null +++ b/classpath/java/util/TreeMap.java @@ -0,0 +1,197 @@ +/* Copyright (c) 2008, 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 TreeMap implements Map { + private TreeSet> set; + + public TreeMap(final Comparator comparator) { + set = new TreeSet(new Comparator>() { + public int compare(MyEntry a, MyEntry b) { + return comparator.compare(a.key, b.key); + } + }); + } + + public TreeMap() { + this(new Comparator() { + public int compare(K a, K b) { + return ((Comparable) a).compareTo(b); + } + }); + } + + public String toString() { + return Collections.toString(this); + } + + public V get(Object key) { + MyEntry e = set.find(new MyEntry(key, null)); + return e == null ? null : e.value; + } + + public V put(K key, V value) { + MyEntry e = set.addAndReplace(new MyEntry(key, value)); + return e == null ? null : e.value; + } + + public void putAll(Map elts) { + for (Map.Entry entry : elts.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + public V remove(Object key) { + MyEntry e = set.removeAndReturn(new MyEntry(key, null)); + return e == null ? null : e.value; + } + + public void clear() { + set.clear(); + } + + public int size() { + return set.size(); + } + + public boolean isEmpty() { + return size() == 0; + } + + public boolean containsKey(Object key) { + return set.contains(new MyEntry(key, null)); + } + + private boolean equal(Object a, Object b) { + return a == null ? b == null : a.equals(b); + } + + public boolean containsValue(Object value) { + for (V v: values()) { + if (equal(v, value)) { + return true; + } + } + return false; + } + + public Set> entrySet() { + return (Set>) (Set) set; + } + + public Set keySet() { + return new KeySet(); + } + + public Collection values() { + return new Values(); + } + + private static class MyEntry implements Entry { + public final K key; + public V value; + + public MyEntry(K key, V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } + } + + private class KeySet implements Set { + public int size() { + return TreeMap.this.size(); + } + + public boolean isEmpty() { + return TreeMap.this.isEmpty(); + } + + public boolean contains(Object key) { + return containsKey(key); + } + + public boolean add(K key) { + return set.addAndReplace(new MyEntry(key, null)) != null; + } + + public boolean addAll(Collection collection) { + boolean change = false; + for (K k: collection) if (add(k)) change = true; + return change; + } + + public boolean remove(Object key) { + return set.removeAndReturn(new MyEntry(key, null)) != null; + } + + public T[] toArray(T[] array) { + return Collections.toArray(this, array); + } + + public void clear() { + TreeMap.this.clear(); + } + + public Iterator iterator() { + return new Collections.KeyIterator(set.iterator()); + } + } + + private class Values implements Collection { + public int size() { + return TreeMap.this.size(); + } + + public boolean isEmpty() { + return TreeMap.this.isEmpty(); + } + + public boolean contains(Object value) { + return containsValue(value); + } + + 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 T[] toArray(T[] array) { + return Collections.toArray(this, array); + } + + public void clear() { + TreeMap.this.clear(); + } + + public Iterator iterator() { + return new Collections.ValueIterator(set.iterator()); + } + } +} diff --git a/classpath/java/util/TreeSet.java b/classpath/java/util/TreeSet.java index 4940eb0d22..3c63160b99 100644 --- a/classpath/java/util/TreeSet.java +++ b/classpath/java/util/TreeSet.java @@ -10,7 +10,7 @@ package java.util; -public class TreeSet extends AbstractSet implements Collection { +public class TreeSet extends AbstractSet implements Collection { private PersistentSet> set; private int size; @@ -49,34 +49,52 @@ public class TreeSet extends AbstractSet implements Collection { return false; } - // Used by hashMaps for replacement - public void addAndReplace(T value) { + T addAndReplace(T value) { PersistentSet.Path> p = set.find(new Cell(value, null)); if (p.fresh()) { set = p.add(); ++size; + return null; } else { + T old = p.value().value; set = p.replaceWith(new Cell(value, null)); + return old; } } - public boolean remove(Object value) { + T find(T value) { + PersistentSet.Path> p = set.find(new Cell(value, null)); + return p.fresh() ? null : p.value().value; + } + + T removeAndReturn(T value) { + Cell cell = removeCell(value); + return cell == null ? null : cell.value; + } + + private Cell removeCell(Object value) { PersistentSet.Path> p = set.find(new Cell(value, null)); if (p.fresh()) { - return false; + return null; } else { --size; + Cell old = p.value(); + if (p.value().next != null) { set = p.replaceWith(p.value().next); } else { set = p.remove(); } - return true; + return old; } } + public boolean remove(Object value) { + return removeCell(value) != null; + } + public int size() { return size; } diff --git a/test/Tree.java b/test/Tree.java index 5d4ad83d0c..55858ab8d7 100644 --- a/test/Tree.java +++ b/test/Tree.java @@ -1,5 +1,8 @@ import java.util.Comparator; import java.util.TreeSet; +import java.util.TreeMap; +import java.util.Map; +import java.util.Iterator; public class Tree { private static void expect(boolean v) { @@ -17,6 +20,21 @@ public class Tree { return sb.toString(); } + private static String printMap(TreeMap map) { + StringBuilder sb = new StringBuilder(); + + for (Iterator it = map.entrySet().iterator(); it.hasNext();) { + Map.Entry e = it.next(); + sb.append(e.getKey()); + sb.append("="); + sb.append(e.getValue()); + if (it.hasNext()) { + sb.append(", "); + } + } + return sb.toString(); + } + private static void isEqual(String s1, String s2) { System.out.println(s1); expect(s1.equals(s2)); @@ -53,5 +71,43 @@ public class Tree { expect(t2.size() == 6); t2.add("kappa"); isEqual(printList(t2), "999, five, four, kappa, one, three, two"); + + TreeMap map = new TreeMap + (new Comparator() { + public int compare(String s1, String s2) { + return s1.compareTo(s2); + } + }); + + map.put("q", "Q"); + map.put("a", "A"); + map.put("b", "B"); + map.put("z", "Z"); + map.put("c", "C"); + map.put("y", "Y"); + + isEqual(printMap(map), "a=A, b=B, c=C, q=Q, y=Y, z=Z"); + } + + private static class MyEntry implements Map.Entry { + public final K key; + public V value; + + public MyEntry(K key, V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + public void setValue(V value) { + this.value = value; + } } }