diff --git a/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMap.java b/gson/src/main/java/com/google/gson/internal/LinkedHashTreeMap.java similarity index 96% rename from gson/src/test/java/com/google/gson/internal/LinkedHashTreeMap.java rename to gson/src/main/java/com/google/gson/internal/LinkedHashTreeMap.java index 18549675..098cb016 100644 --- a/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMap.java +++ b/gson/src/main/java/com/google/gson/internal/LinkedHashTreeMap.java @@ -38,8 +38,6 @@ import java.util.Set; * LinkedHashMap classes. */ public final class LinkedHashTreeMap extends AbstractMap implements Serializable { - private static final int MAX_CAPACITY = 8192; - @SuppressWarnings({ "unchecked", "rawtypes" }) // to avoid Comparable>> private static final Comparator NATURAL_ORDER = new Comparator() { public int compare(Comparable a, Comparable b) { @@ -566,15 +564,10 @@ public final class LinkedHashTreeMap extends AbstractMap implements * twice as many trees, each of (approximately) half the previous size. */ static Node[] doubleCapacity(Node[] oldTable) { + // TODO: don't do anything if we're already at MAX_CAPACITY int oldCapacity = oldTable.length; - if (oldCapacity >= MAX_CAPACITY) { - return oldTable; - } - - int newCapacity = oldCapacity * 2; - @SuppressWarnings("unchecked") // Arrays and generics don't get along. - Node[] newTable = new Node[newCapacity]; + Node[] newTable = new Node[oldCapacity * 2]; AvlIterator iterator = new AvlIterator(); AvlBuilder leftBuilder = new AvlBuilder(); AvlBuilder rightBuilder = new AvlBuilder(); @@ -591,7 +584,7 @@ public final class LinkedHashTreeMap extends AbstractMap implements int leftSize = 0; int rightSize = 0; for (Node node; (node = iterator.next()) != null; ) { - if ((node.hash & (newCapacity - 1)) == i) { + if ((node.hash & oldCapacity) == 0) { leftSize++; } else { rightSize++; @@ -599,30 +592,20 @@ public final class LinkedHashTreeMap extends AbstractMap implements } // Split the tree into two. - Node leftRoot = null; - Node rightRoot = null; - if (leftSize > 0 && rightSize > 0) { - leftBuilder.reset(leftSize); - rightBuilder.reset(rightSize); - iterator.reset(root); - for (Node node; (node = iterator.next()) != null; ) { - if ((node.hash & (newCapacity - 1)) == i) { - leftBuilder.add(node); - } else { - rightBuilder.add(node); - } + leftBuilder.reset(leftSize); + rightBuilder.reset(rightSize); + iterator.reset(root); + for (Node node; (node = iterator.next()) != null; ) { + if ((node.hash & oldCapacity) == 0) { + leftBuilder.add(node); + } else { + rightBuilder.add(node); } - leftRoot = leftBuilder.root(); - rightRoot = rightBuilder.root(); - } else if (leftSize > 0) { - leftRoot = root; - } else { - rightRoot = root; } // Populate the enlarged array with these new roots. - newTable[i] = leftRoot; - newTable[i + oldCapacity] = rightRoot; + newTable[i] = leftSize > 0 ? leftBuilder.root() : null; + newTable[i + oldCapacity] = rightSize > 0 ? rightBuilder.root() : null; } return newTable; } diff --git a/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java b/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java index 62e19b80..2ba7ec2a 100644 --- a/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java +++ b/gson/src/test/java/com/google/gson/internal/LinkedHashTreeMapTest.java @@ -20,14 +20,12 @@ import com.google.gson.common.MoreAsserts; import com.google.gson.internal.LinkedHashTreeMap.AvlBuilder; import com.google.gson.internal.LinkedHashTreeMap.AvlIterator; import com.google.gson.internal.LinkedHashTreeMap.Node; - -import junit.framework.TestCase; - import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.Random; +import junit.framework.TestCase; public final class LinkedHashTreeMapTest extends TestCase { public void testIterationOrder() { @@ -104,7 +102,7 @@ public final class LinkedHashTreeMapTest extends TestCase { // NOTE that this does not happen every time, but given the below predictable random, // this test will consistently fail (assuming the initial size is 16 and rehashing // size remains at 3/4) - public void disabled_testForceDoublingAndRehash() throws Exception { + public void testForceDoublingAndRehash() throws Exception { Random random = new Random(1367593214724L); LinkedHashTreeMap map = new LinkedHashTreeMap(); String[] keys = new String[1000]; @@ -209,6 +207,16 @@ public final class LinkedHashTreeMapTest extends TestCase { Node[] newTable = LinkedHashTreeMap.doubleCapacity(oldTable); assertTree("(b d f)", newTable[0]); // Even hash codes! assertTree("(a c (. e g))", newTable[1]); // Odd hash codes! + } + + public void testDoubleCapacityAllNodesOnLeft() { + @SuppressWarnings("unchecked") // Arrays and generics don't get along. + Node[] oldTable = new Node[1]; + oldTable[0] = node(node("b"), "d", node("f")); + + Node[] newTable = LinkedHashTreeMap.doubleCapacity(oldTable); + assertTree("(b d f)", newTable[0]); // Even hash codes! + assertNull(newTable[1]); // Odd hash codes! for (Node node : newTable) { if (node != null) {