From 8a4d3effe0d4a4f83ed855d824aecbe770a1a2a2 Mon Sep 17 00:00:00 2001 From: Eric Scharff Date: Fri, 28 Sep 2007 11:00:31 -0600 Subject: [PATCH 1/7] Make String.compare() match the Java specification --- classpath/java/lang/String.java | 43 +++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index 283e4b7248..94c7339673 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -89,36 +89,37 @@ public final class String implements Comparable { public int compareTo(String s) { if (this == s) return 0; - int d = length - s.length; - if (d != 0) { - return d; - } else { - for (int i = 0; i < length; ++i) { - d = charAt(i) - s.charAt(i); - if (d != 0) { - return d; - } + int idx = 0; + int result; + + int end = (length < s.length ? length : s.length); + + while (idx < end) { + if ((result = charAt(idx) - s.charAt(idx)) != 0) { + return result; } - return 0; + idx++; } + return length - s.length; } public int compareToIgnoreCase(String s) { if (this == s) return 0; - int d = length - s.length; - if (d != 0) { - return d; - } else { - for (int i = 0; i < length; ++i) { - d = Character.toLowerCase(charAt(i)) - - Character.toLowerCase(s.charAt(i)); - if (d != 0) { - return d; - } + int idx = 0; + int result; + + int end = (length < s.length ? length : s.length); + + while (idx < end) { + if ((result = + Character.toLowerCase(charAt(idx)) - + Character.toLowerCase(s.charAt(idx))) != 0) { + return result; } - return 0; + idx++; } + return length - s.length; } public String trim() { From 5691ec87f09b14e7f871947a3ed5fa0e9663e18d Mon Sep 17 00:00:00 2001 From: Eric Scharff Date: Fri, 28 Sep 2007 11:01:57 -0600 Subject: [PATCH 2/7] Added a proper implementation of TreeSet, based on a Persistent set implementation. --- classpath/java/util/Cell.java | 24 + classpath/java/util/PersistentSet.java | 590 +++++++++++++++++++++++++ classpath/java/util/TreeSet.java | 168 ++++--- test/Tree.java | 37 +- 4 files changed, 750 insertions(+), 69 deletions(-) create mode 100644 classpath/java/util/Cell.java create mode 100644 classpath/java/util/PersistentSet.java diff --git a/classpath/java/util/Cell.java b/classpath/java/util/Cell.java new file mode 100644 index 0000000000..4cd6ec593a --- /dev/null +++ b/classpath/java/util/Cell.java @@ -0,0 +1,24 @@ +package java.util; + +public class Cell { + public T value; + public Cell next; + + public Cell(T value, Cell next) { + this.value = value; + this.next = next; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (Cell c = this; c != null; c = c.next) { + sb.append(value); + if (c.next != null) { + sb.append(" "); + } + } + sb.append(")"); + return sb.toString(); + } +} diff --git a/classpath/java/util/PersistentSet.java b/classpath/java/util/PersistentSet.java new file mode 100644 index 0000000000..74cf5f4a5c --- /dev/null +++ b/classpath/java/util/PersistentSet.java @@ -0,0 +1,590 @@ +package java.util; + +import java.util.Comparator; +import java.lang.Iterable; + +public class PersistentSet implements Iterable { + private static final Node NullNode = new Node(null); + + static { + NullNode.left = NullNode; + NullNode.right = NullNode; + } + + private final Node root; + private final Comparator comparator; + private final int size; + + public PersistentSet() { + this(NullNode, new Comparator() { + public int compare(T a, T b) { + return ((Comparable) a).compareTo(b); + } + }, 0); + } + + public PersistentSet(Comparator comparator) { + this(NullNode, comparator, 0); + } + + private PersistentSet(Node root, Comparator comparator, int size) { + this.root = root; + this.comparator = comparator; + this.size = size; + } + + public Comparator comparator() { + return comparator; + } + + public PersistentSet add(T value) { + return add(value, false); + } + + public int size() { + return size; + } + + public PersistentSet add(T value, boolean replaceExisting) { + Path p = find(value); + if (! p.fresh) { + if (replaceExisting) { + return p.replaceWith(value); + } else { + return this; + } + } + + return add(p); + } + + private PersistentSet add(Path p) { + if (! p.fresh) throw new IllegalArgumentException(); + + Node new_ = p.node; + Node newRoot = p.root.root; + Cell> ancestors = p.ancestors; + + // rebalance + new_.red = true; + while (ancestors != null && ancestors.value.red) { + if (ancestors.value == ancestors.next.value.left) { + if (ancestors.next.value.right.red) { + ancestors.value.red = false; + ancestors.next.value.right = new Node(ancestors.next.value.right); + ancestors.next.value.right.red = false; + ancestors.next.value.red = true; + new_ = ancestors.next.value; + ancestors = ancestors.next.next; + } else { + if (new_ == ancestors.value.right) { + new_ = ancestors.value; + ancestors = ancestors.next; + + Node n = leftRotate(new_); + if (ancestors.value.right == new_) { + ancestors.value.right = n; + } else { + ancestors.value.left = n; + } + ancestors = new Cell(n, ancestors); + } + ancestors.value.red = false; + ancestors.next.value.red = true; + + Node n = rightRotate(ancestors.next.value); + if (ancestors.next.next == null) { + newRoot = n; + } else if (ancestors.next.next.value.right == ancestors.next.value) { + ancestors.next.next.value.right = n; + } else { + ancestors.next.next.value.left = n; + } + // done + } + } else { + if (ancestors.next.value.left.red) { + ancestors.value.red = false; + ancestors.next.value.left = new Node(ancestors.next.value.left); + ancestors.next.value.left.red = false; + ancestors.next.value.red = true; + new_ = ancestors.next.value; + ancestors = ancestors.next.next; + } else { + if (new_ == ancestors.value.left) { + new_ = ancestors.value; + ancestors = ancestors.next; + + Node n = rightRotate(new_); + if (ancestors.value.right == new_) { + ancestors.value.right = n; + } else { + ancestors.value.left = n; + } + ancestors = new Cell(n, ancestors); + } + ancestors.value.red = false; + ancestors.next.value.red = true; + + Node n = leftRotate(ancestors.next.value); + if (ancestors.next.next == null) { + newRoot = n; + } else if (ancestors.next.next.value.right == ancestors.next.value) { + ancestors.next.next.value.right = n; + } else { + ancestors.next.next.value.left = n; + } + // done + } + } + } + + newRoot.red = false; + + return new PersistentSet(newRoot, comparator, size + 1); + } + + private static Node leftRotate(Node n) { + Node child = new Node(n.right); + n.right = child.left; + child.left = n; + return child; + } + + private static Node rightRotate(Node n) { + Node child = new Node(n.left); + n.left = child.right; + child.right = n; + return child; + } + + public PersistentSet remove(T value) { + Path p = find(value); + if (! p.fresh) { + return remove(p); + } + + return this; + } + + private PersistentSet remove(Path p) { + Node new_ = p.node; + Node newRoot = p.root.root; + Cell> ancestors = p.ancestors; + + Node dead; + if (new_.left == NullNode || new_.right == NullNode) { + dead = new_; + } else { + Cell> path = successor(new_, ancestors); + dead = path.value; + ancestors = path.next; + } + + Node child; + if (dead.left != NullNode) { + child = dead.left; + } else { + child = dead.right; + } + + if (ancestors == null) { + child.red = false; + return new PersistentSet(child, comparator, 1); + } else if (dead == ancestors.value.left) { + ancestors.value.left = child; + } else { + ancestors.value.right = child; + } + + if (dead != new_) { + new_.value = dead.value; + } + + if (! dead.red) { + // rebalance + while (ancestors != null && ! child.red) { + if (child == ancestors.value.left) { + Node sibling = ancestors.value.right + = new Node(ancestors.value.right); + if (sibling.red) { + sibling.red = false; + ancestors.value.red = true; + + Node n = leftRotate(ancestors.value); + if (ancestors.next == null) { + newRoot = n; + } else if (ancestors.next.value.right == ancestors.value) { + ancestors.next.value.right = n; + } else { + ancestors.next.value.left = n; + } + ancestors.next = new Cell(n, ancestors.next); + + sibling = ancestors.value.right; + } + + if (! (sibling.left.red || sibling.right.red)) { + sibling.red = true; + child = ancestors.value; + ancestors = ancestors.next; + } else { + if (! sibling.right.red) { + sibling.left = new Node(sibling.left); + sibling.left.red = false; + + sibling.red = true; + sibling = ancestors.value.right = rightRotate(sibling); + } + + sibling.red = ancestors.value.red; + ancestors.value.red = false; + + sibling.right = new Node(sibling.right); + sibling.right.red = false; + + Node n = leftRotate(ancestors.value); + if (ancestors.next == null) { + newRoot = n; + } else if (ancestors.next.value.right == ancestors.value) { + ancestors.next.value.right = n; + } else { + ancestors.next.value.left = n; + } + + child = newRoot; + ancestors = null; + } + } else { + Node sibling = ancestors.value.left + = new Node(ancestors.value.left); + if (sibling.red) { + sibling.red = false; + ancestors.value.red = true; + + Node n = rightRotate(ancestors.value); + if (ancestors.next == null) { + newRoot = n; + } else if (ancestors.next.value.left == ancestors.value) { + ancestors.next.value.left = n; + } else { + ancestors.next.value.right = n; + } + ancestors.next = new Cell(n, ancestors.next); + + sibling = ancestors.value.left; + } + + if (! (sibling.right.red || sibling.left.red)) { + sibling.red = true; + child = ancestors.value; + ancestors = ancestors.next; + } else { + if (! sibling.left.red) { + sibling.right = new Node(sibling.right); + sibling.right.red = false; + + sibling.red = true; + sibling = ancestors.value.left = leftRotate(sibling); + } + + sibling.red = ancestors.value.red; + ancestors.value.red = false; + + sibling.left = new Node(sibling.left); + sibling.left.red = false; + + Node n = rightRotate(ancestors.value); + if (ancestors.next == null) { + newRoot = n; + } else if (ancestors.next.value.left == ancestors.value) { + ancestors.next.value.left = n; + } else { + ancestors.next.value.right = n; + } + + child = newRoot; + ancestors = null; + } + } + } + + child.red = false; + } + + return new PersistentSet(newRoot, comparator, size - 1); + } + + private static Cell> minimum(Node n, + Cell> ancestors) + { + while (n.left != NullNode) { + n.left = new Node(n.left); + ancestors = new Cell(n, ancestors); + n = n.left; + } + + return new Cell(n, ancestors); + } + + private static Cell> successor(Node n, + Cell> ancestors) + { + if (n.right != NullNode) { + n.right = new Node(n.right); + return minimum(n.right, new Cell(n, ancestors)); + } + + while (ancestors != null && n == ancestors.value.right) { + n = ancestors.value; + ancestors = ancestors.next; + } + + return ancestors; + } + + public Path find(T value) { + Node newRoot = new Node(root); + Cell> ancestors = null; + + Node old = root; + Node new_ = newRoot; + while (old != NullNode) { + ancestors = new Cell(new_, ancestors); + + int difference = comparator.compare(value, old.value); + if (difference < 0) { + old = old.left; + new_ = new_.left = new Node(old); + } else if (difference > 0) { + old = old.right; + new_ = new_.right = new Node(old); + } else { + return new Path(false, new_, + new PersistentSet(newRoot, comparator, size), + ancestors.next); + } + } + + new_.value = value; + return new Path(true, new_, + new PersistentSet(newRoot, comparator, size), + ancestors); + } + + public Path first() { + if (root == NullNode) return null; + + Node newRoot = new Node(root); + Cell> ancestors = null; + + Node old = root; + Node new_ = newRoot; + while (old.left != NullNode) { + ancestors = new Cell(new_, ancestors); + + old = old.left; + new_ = new_.left = new Node(old); + } + + return new Path(true, new_, + new PersistentSet(newRoot, comparator, size), + ancestors); + } + + public Path last() { + if (root == NullNode) return null; + + Node newRoot = new Node(root); + Cell> ancestors = null; + + Node old = root; + Node new_ = newRoot; + while (old.right != NullNode) { + ancestors = new Cell(new_, ancestors); + + old = old.right; + new_ = new_.right = new Node(old); + } + + return new Path(true, new_, + new PersistentSet(newRoot, comparator, size), + ancestors); + } + + public java.util.Iterator iterator() { + return new Iterator(first()); + } + + private Path successor(Path p) { + Cell> s = successor(p.node, p.ancestors); + if (s == null) { + return null; + } else { + return new Path(false, s.value, p.root, s.next); + } + } + +// public void dump(java.io.PrintStream out) { +// dump(root, out, 0); +// } + +// private static void indent(java.io.PrintStream out, int level) { +// for (int i = 0; i < level; ++i) out.print(" "); +// } + +// private static void dump(Node n, java.io.PrintStream out, int level) { +// indent(out, level); +// out.print(n == NullNode ? null : n.value); +// out.println(n == NullNode ? "" : n.red ? " (red)" : " (black)"); +// if (n.left != NullNode || n.right != NullNode) { +// dump(n.left, out, level + 1); +// dump(n.right, out, level + 1); +// } +// } + +// private static int[] randomSet(java.util.Random r, int size) { +// int[] data = new int[size]; +// for (int i = size - 1; i >= 0; --i) { +// data[i] = i + 1; +// } + +// for (int i = size - 1; i >= 0; --i) { +// int n = r.nextInt(size); +// int tmp = data[i]; +// data[i] = data[n]; +// data[n] = tmp; +// } + +// return data; +// } + +// public static void main(String[] args) { +// java.util.Random r = new java.util.Random(Integer.parseInt(args[0])); +// int size = 18; +// PersistentSet[] sets = new PersistentSet[size]; +// PersistentSet s = new PersistentSet(); + +// int[] data = randomSet(r, size); + +// for (int i = 0; i < size; ++i) { +// System.out.println("-- add " + data[i] + " -- "); +// sets[i] = s = s.add(data[i]); +// dump(s.root, System.out, 0); +// } + +// System.out.println("\npersistence:\n"); +// for (int i = 0; i < size; ++i) { +// dump(sets[i].root, System.out, 0); +// System.out.println("--"); +// } + +// data = randomSet(r, size); + +// System.out.println("\nremoval:\n"); +// for (int i = 0; i < size; ++i) { +// System.out.println("-- remove " + data[i] + " -- "); +// sets[i] = s = s.remove(data[i]); +// dump(s.root, System.out, 0); +// } + +// System.out.println("\npersistence:\n"); +// for (int i = 0; i < size; ++i) { +// dump(sets[i].root, System.out, 0); +// System.out.println("--"); +// } +// } + + private static class Node { + public T value; + public Node left; + public Node right; + public boolean red; + + public Node(Node basis) { + if (basis != null) { + value = basis.value; + left = basis.left; + right = basis.right; + red = basis.red; + } + } + } + + public static class Path { + private final boolean fresh; + private final Node node; + private final PersistentSet root; + private final Cell> ancestors; + + public Path(boolean fresh, Node node, PersistentSet root, + Cell> ancestors) + { + this.fresh = fresh; + this.node = node; + this.root = root; + this.ancestors = ancestors; + } + + public T value() { + return node.value; + } + + public boolean fresh() { + return fresh; + } + + public PersistentSet root() { + return root; + } + + public Path successor() { + return root.successor(this); + } + + public PersistentSet remove() { + return root.remove(this); + } + + public PersistentSet add() { + if (! fresh) throw new IllegalStateException(); + + return root.add(this); + } + + public PersistentSet replaceWith(T value) { + if (fresh) throw new IllegalStateException(); + if (root.comparator.compare(node.value, value) != 0) + throw new IllegalArgumentException(); + + node.value = value; + return root; + } + } + + public class Iterator implements java.util.Iterator { + private PersistentSet.Path path; + + private Iterator(PersistentSet.Path path) { + this.path = path; + } + + private Iterator(Iterator start) { + path = start.path; + } + + public boolean hasNext() { + return path != null; + } + + public T next() { + PersistentSet.Path p = path; + path = path.successor(); + return p.value(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/classpath/java/util/TreeSet.java b/classpath/java/util/TreeSet.java index 69d1b4a715..a35fe754ff 100644 --- a/classpath/java/util/TreeSet.java +++ b/classpath/java/util/TreeSet.java @@ -1,81 +1,131 @@ package java.util; public class TreeSet implements Iterable { - private final Comparator comparator; + private PersistentSet> set; private int size; - private Cell root; - public TreeSet(Comparator comparator) { - this.comparator = comparator; - size=0; - root=null; + public TreeSet(final Comparator comparator) { + set = new PersistentSet(new Comparator>() { + public int compare(Cell a, Cell b) { + return comparator.compare(a.value, b.value); + } + }); + size = 0; } public Iterator iterator() { - return walk().iterator(); + return new MyIterator(set.first()); } - private ArrayList walk() { - return walk(root, new ArrayList(size)); - } - - private ArrayList walk(Cell cell, ArrayList list) { - if (cell != null) { - walk(cell.left, list); - list.add(cell.value); - walk(cell.right, list); - } - return list; - } - - public boolean add(T o) { - ++size; - if (root == null) { - root = new Cell(o); + public boolean add(T value) { + PersistentSet.Path> p = set.find(new Cell(value, null)); + if (p.fresh()) { + set = p.add(); + ++size; return true; - } else { - Cell newElt = new Cell(o); - Cell cur = root; - do { - int result = comparator.compare(o, cur.value); - if (result == 0) return false; - if (result < 0) { - if (cur.left == null) { - newElt.parent = cur; - cur.left = newElt; - return false; - } else { - cur = cur.left; - } - } else { - if (cur.right == null) { - newElt.parent = cur; - cur.right = newElt; - return false; - } else { - cur = cur.right; - } - } - } while (cur != null); - throw new RuntimeException("Fell off end of TreeSet"); } + return false; } - public boolean remove(T o) { - throw new UnsupportedOperationException(); + // Used by hashMaps for replacement + public void addAndReplace(T value) { + PersistentSet.Path> p = set.find(new Cell(value, null)); + if (p.fresh()) { + set = p.add(); + ++size; + } else { + set = p.replaceWith(new Cell(value, null)); + } + } + + public boolean remove(T value) { + PersistentSet.Path> p = set.find(new Cell(value, null)); + if (p.fresh()) { + return false; + } else { + --size; + + if (p.value().next != null) { + set = p.replaceWith(p.value().next); + } else { + set = p.remove(); + } + + return true; + } } public int size() { return size; } - private static class Cell { - public final T value; - public Cell parent; - public Cell left; - public Cell right; - public Cell(T val) { - value = val; + private class MyIterator implements java.util.Iterator { + private PersistentSet.Path> path; + private PersistentSet.Path> nextPath; + private Cell cell; + private Cell prevCell; + private Cell prevPrevCell; + private boolean canRemove = false; + + private MyIterator(PersistentSet.Path> path) { + this.path = path; + if (path != null) { + cell = path.value(); + nextPath = path.successor(); + } } - } + + private MyIterator(MyIterator start) { + path = start.path; + nextPath = start.nextPath; + cell = start.cell; + prevCell = start.prevCell; + prevPrevCell = start.prevPrevCell; + canRemove = start.canRemove; + } + + public boolean hasNext() { + return cell != null || nextPath != null; + } + + public T next() { + if (cell == null) { + path = nextPath; + nextPath = path.successor(); + cell = path.value(); + } + prevPrevCell = prevCell; + prevCell = cell; + cell = cell.next; + canRemove = true; + return prevCell.value; + } + + public void remove() { + if (! canRemove) throw new IllegalStateException(); + + --size; + + if (prevPrevCell != null && prevPrevCell.next == prevCell) { + // cell to remove is not the first in the list. + prevPrevCell.next = prevCell.next; + prevCell = prevPrevCell; + } else if (prevCell.next == cell && cell != null) { + // cell to remove is the first in the list, but not the last. + set = (PersistentSet) path.replaceWith(cell); + prevCell = null; + } else { + // cell is alone in the list. + set = (PersistentSet) path.remove(); + path = path.successor(); + if (path != null) { + prevCell = null; + cell = path.value(); + path = (PersistentSet.Path) set.find((Cell) cell); + } + } + + canRemove = false; + } + } } diff --git a/test/Tree.java b/test/Tree.java index 780af9832d..5d4ad83d0c 100644 --- a/test/Tree.java +++ b/test/Tree.java @@ -6,11 +6,11 @@ public class Tree { if (! v) throw new RuntimeException(); } - private static String printList(TreeSet list) { + private static String printList(TreeSet list) { StringBuilder sb = new StringBuilder(); - for (Integer i : list) { - sb.append(i); + for (Object o : list) { + sb.append(o); sb.append(", "); } sb.setLength(sb.length()-2); @@ -29,12 +29,29 @@ public class Tree { } public static void main(String args[]) { - TreeSet l = new TreeSet(new MyCompare()); - l.add(5); l.add(2); l.add(1); l.add(8); l.add(3); - isEqual(printList(l), "1, 2, 3, 5, 8"); - l.add(4); - isEqual(printList(l), "1, 2, 3, 4, 5, 8"); - l.remove(3); - isEqual(printList(l), "1, 2, 4, 5, 8"); + TreeSet t1 = new TreeSet(new MyCompare()); + t1.add(5); t1.add(2); t1.add(1); t1.add(8); t1.add(3); + isEqual(printList(t1), "1, 2, 3, 5, 8"); + t1.add(4); + isEqual(printList(t1), "1, 2, 3, 4, 5, 8"); + t1.remove(3); + isEqual(printList(t1), "1, 2, 4, 5, 8"); + TreeSet t2 = new TreeSet(new Comparator() { + public int compare(String s1, String s2) { + return s1.compareTo(s2); + } + }); + t2.add("one"); t2.add("two"); t2.add("three"); t2.add("four"); t2.add("five"); + isEqual(printList(t2), "five, four, one, three, two"); + for (int i=0; i < 1000; i++) { + t2.add(Integer.toString(i)); + } + expect(t2.size() == 1005); + for (int i=0; i < 999; i++) { + t2.remove(Integer.toString(i)); + } + expect(t2.size() == 6); + t2.add("kappa"); + isEqual(printList(t2), "999, five, four, kappa, one, three, two"); } } From 43a2cb7cc5a3dbaa4093d2a337e859bb36171502 Mon Sep 17 00:00:00 2001 From: Eric Scharff Date: Fri, 28 Sep 2007 11:38:58 -0600 Subject: [PATCH 3/7] Tie up some loose ends, implementing methods that are useful but not yet implemented. --- classpath/java/lang/Math.java | 5 +---- classpath/java/util/Calendar.java | 2 +- classpath/java/util/Properties.java | 12 +++++++++++- classpath/java/util/zip/Inflater.java | 9 +++++++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/classpath/java/lang/Math.java b/classpath/java/lang/Math.java index 2d3f2bbad4..9ad1f139ed 100644 --- a/classpath/java/lang/Math.java +++ b/classpath/java/lang/Math.java @@ -62,10 +62,7 @@ public final class Math { return (int) Math.floor(v + 0.5); } - public static double random() { - // TODO - throw new UnsupportedOperationException(); - } + public static native double random(); public static native double floor(double v); diff --git a/classpath/java/util/Calendar.java b/classpath/java/util/Calendar.java index a57bf03066..640b7a237a 100644 --- a/classpath/java/util/Calendar.java +++ b/classpath/java/util/Calendar.java @@ -35,7 +35,7 @@ public abstract class Calendar { } public void setTime(Date date) { - // TODO + time = date.getTime(); } public abstract void roll(int field, boolean up); diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index 41a37bc303..8a9fe5892f 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -2,6 +2,7 @@ package java.util; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintStream; import java.io.IOException; public class Properties extends Hashtable { @@ -10,7 +11,16 @@ public class Properties extends Hashtable { } public void store(OutputStream out, String comment) throws IOException { - // TODO + PrintStream os = new PrintStream(out); + os.println("# " + comment); + for (Iterator it = entrySet().iterator(); + it.hasNext();) { + Map.Entry entry = (Map.Entry)it.next(); + os.print(entry.getKey()); + os.print('='); + os.println(entry.getValue()); + } + os.flush(); } public String getProperty(String key) { diff --git a/classpath/java/util/zip/Inflater.java b/classpath/java/util/zip/Inflater.java index 4969f79637..ecb32b6320 100644 --- a/classpath/java/util/zip/Inflater.java +++ b/classpath/java/util/zip/Inflater.java @@ -15,8 +15,10 @@ public class Inflater { private int length; private boolean needDictionary; private boolean finished; + private final boolean nowrap; public Inflater(boolean nowrap) { + this.nowrap = nowrap; peer = make(nowrap); } @@ -55,8 +57,11 @@ public class Inflater { } public void reset() { - // TODO - throw new UnsupportedOperationException(); + dispose(); + peer = make(nowrap); + input = null; + offset = length = 0; + needDictionary = finished = false; } public int inflate(byte[] output) throws DataFormatException { From b4afc538d41a0bc42df360c50afafaee587eb8fd Mon Sep 17 00:00:00 2001 From: Eric Scharff Date: Fri, 28 Sep 2007 12:16:25 -0600 Subject: [PATCH 4/7] (Hopefully correct) implementation of ByteBuffer --- classpath/java/nio/ByteBuffer.java | 159 +++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 classpath/java/nio/ByteBuffer.java diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java new file mode 100644 index 0000000000..79517343ab --- /dev/null +++ b/classpath/java/nio/ByteBuffer.java @@ -0,0 +1,159 @@ +package java.nio; + +public class ByteBuffer { + private final byte[] array; + private int arrayOffset; + private int capacity; + private int position; + private int limit; + + public static ByteBuffer allocate(int capacity) { + return new ByteBuffer(new byte[capacity]); + } + + public static ByteBuffer wrap(byte[] array) { + return new ByteBuffer(array); + } + + private ByteBuffer(byte[] array) { + this.array = array; + arrayOffset = 0; + capacity = array.length; + limit = capacity; + position = 0; + } + + public byte[] array() { + return array; + } + + public ByteBuffer slice() { + ByteBuffer buf = new ByteBuffer(array); + buf.arrayOffset = arrayOffset + position; + buf.position = 0; + buf.capacity = capacity - position; + buf.limit = buf.capacity; + return buf; + } + + public int limit() { + return limit; + } + + public int remaining() { + return limit-position; + } + + public int position() { + return position; + } + + public int capacity() { + return capacity; + } + + public int arrayOffset() { + return arrayOffset; + } + + public ByteBuffer compact() { + if (position != 0) { + System.arraycopy(array, arrayOffset+position, array, arrayOffset, remaining()); + } + return this; + } + + public ByteBuffer limit(int newLimit) { + limit = newLimit; + return this; + } + + public ByteBuffer position(int newPosition) { + position = newPosition; + return this; + } + + public ByteBuffer put(byte val) { + array[position++] = val; + return this; + } + + public ByteBuffer put(ByteBuffer src) { + put(src.array, src.arrayOffset + src.position, src.remaining()); + position += src.remaining(); + return this; + } + + public ByteBuffer put(byte[] arr) { + return put(arr, 0, arr.length); + } + + public ByteBuffer put(byte[] arr, int offset, int len) { + System.arraycopy(arr, offset, array, arrayOffset, len); + position += len; + return this; + } + + public ByteBuffer putInt(int position, int val) { + array[arrayOffset+position] = (byte)((val >> 24) & 0xff); + array[arrayOffset+position+1] = (byte)((val >> 16) & 0xff); + array[arrayOffset+position+2] = (byte)((val >> 8) & 0xff); + array[arrayOffset+position+3] = (byte)((val ) & 0xff); + return this; + } + + public ByteBuffer putInt(int val) { + putInt(position, val); + position += 4; + return this; + } + + public ByteBuffer putShort(short val) { + put((byte)((val >> 8) & 0xff)); + put((byte)(val & 0xff)); + return this; + } + + public ByteBuffer putLong(long val) { + putInt((int)(val >> 32)); + putInt((int)val); + return this; + } + + + public boolean hasRemaining() { + return remaining() > 0; + } + + public byte get() { + return array[arrayOffset+(position++)]; + } + + public byte get(int position) { + return array[arrayOffset+position]; + } + + public ByteBuffer flip() { + return this; + } + + public int getInt() { + int i = get() << 24; + i |= (get() & 0xff) << 16; + i |= (get() & 0xff) << 8; + i |= (get() & 0xff); + return i; + } + + public short getShort() { + short s = (short)(get() << 8); + s |= get() & 0xff; + return s; + } + + public long getLong() { + long l = getInt() << 32; + l |= getInt() & 0xffffffff; + return l; + } +} From cc8dd6d8c031261ef00cd8d0f4c108da79d275c9 Mon Sep 17 00:00:00 2001 From: Eric Scharff Date: Fri, 28 Sep 2007 12:18:01 -0600 Subject: [PATCH 5/7] Implemented ByteBuffer.flip() --- classpath/java/nio/ByteBuffer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java index 79517343ab..1b72d70b2a 100644 --- a/classpath/java/nio/ByteBuffer.java +++ b/classpath/java/nio/ByteBuffer.java @@ -134,6 +134,8 @@ public class ByteBuffer { } public ByteBuffer flip() { + limit = position; + position = 0; return this; } From bcd5f5b94bd91eaa6f274b30eb8a39f70730b964 Mon Sep 17 00:00:00 2001 From: Eric Scharff Date: Fri, 28 Sep 2007 12:19:13 -0600 Subject: [PATCH 6/7] Fixed bulk put offset for sliced arrays --- classpath/java/nio/ByteBuffer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java index 1b72d70b2a..4e2018ef77 100644 --- a/classpath/java/nio/ByteBuffer.java +++ b/classpath/java/nio/ByteBuffer.java @@ -89,7 +89,7 @@ public class ByteBuffer { } public ByteBuffer put(byte[] arr, int offset, int len) { - System.arraycopy(arr, offset, array, arrayOffset, len); + System.arraycopy(arr, offset, array, arrayOffset+position, len); position += len; return this; } From da6dd8fba3fc4d582ad2bd3f59ff544963fa97b1 Mon Sep 17 00:00:00 2001 From: Eric Scharff Date: Fri, 28 Sep 2007 13:18:28 -0600 Subject: [PATCH 7/7] Fix ByteBuffer bugs --- classpath/java/nio/ByteBuffer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/classpath/java/nio/ByteBuffer.java b/classpath/java/nio/ByteBuffer.java index 4e2018ef77..dc32fac794 100644 --- a/classpath/java/nio/ByteBuffer.java +++ b/classpath/java/nio/ByteBuffer.java @@ -60,6 +60,7 @@ public class ByteBuffer { if (position != 0) { System.arraycopy(array, arrayOffset+position, array, arrayOffset, remaining()); } + position=0; return this; } @@ -74,7 +75,7 @@ public class ByteBuffer { } public ByteBuffer put(byte val) { - array[position++] = val; + array[arrayOffset+(position++)] = val; return this; }