Revision: 8248
Author: r...@google.com
Date: Mon Jun 14 08:04:23 2010
Log: Add new LongLib test case

Review at http://gwt-code-reviews.appspot.com/607801

Review by: j...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=8248

Added:
 /trunk/dev/core/test/com/google/gwt/lang/LongLibTest.java
Modified:
 /trunk/dev/core/super/com/google/gwt/lang/LongLibBase.java

=======================================
--- /dev/null
+++ /trunk/dev/core/test/com/google/gwt/lang/LongLibTest.java Mon Jun 14 08:04:23 2010
@@ -0,0 +1,826 @@
+package com.google.gwt.lang;
+
+import com.google.gwt.lang.LongEmul;
+
+import junit.framework.TestCase;
+
+import java.util.Random;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class LongLibTest extends TestCase {
+
+  private static abstract class BinaryOp extends Op {
+    public BinaryOp(String name) {
+      super(name);
+    }
+
+    public abstract long ref(long longVal0, long longVal1);
+
+    public abstract LongEmul test(LongEmul longVal0, LongEmul longVal1);
+  }
+
+  private static abstract class BooleanOp extends Op {
+    public BooleanOp(String name) {
+      super(name);
+    }
+
+    public abstract boolean ref(long longVal0, long longVal1);
+
+    public abstract boolean test(LongEmul longVal0, LongEmul longVal1);
+  }
+
+  private static abstract class CompareOp extends Op {
+    public CompareOp(String name) {
+      super(name);
+    }
+
+    public abstract int ref(long longVal0, long longVal1);
+
+    public abstract int test(LongEmul longVal0, LongEmul longVal1);
+  }
+
+  private static abstract class Op {
+    String name;
+
+    public Op(String name) {
+      this.name = name;
+    }
+
+    public String getName() {
+      return name;
+    }
+  }
+
+  private static abstract class ShiftOp extends Op {
+    public ShiftOp(String name) {
+      super(name);
+    }
+
+    public abstract long ref(long longVal, int shift);
+
+    public abstract LongEmul test(LongEmul longVak, int shift);
+  }
+
+  private static abstract class UnaryOp extends Op {
+    public UnaryOp(String name) {
+      super(name);
+    }
+
+    public abstract long ref(long longVal);
+
+    public abstract LongEmul test(LongEmul longVal);
+  }
+
+  private static final int BASE_VALUES = 128;
+
+  private static final BinaryOp OP_ADD = new BinaryOp("ADD") {
+    @Override
+    public long ref(long longVal0, long longVal1) {
+      return longVal0 + longVal1;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.add(longVal0, longVal1);
+    }
+  };
+
+  private static final BinaryOp OP_AND = new BinaryOp("AND") {
+    @Override
+    public long ref(long longVal0, long longVal1) {
+      return longVal0 & longVal1;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.and(longVal0, longVal1);
+    }
+  };
+
+  private static final CompareOp OP_COMPARE = new CompareOp("COMPARE") {
+    @Override
+    public int ref(long longVal0, long longVal1) {
+      if (longVal0 < longVal1) {
+        return -1;
+      }
+      if (longVal0 > longVal1) {
+        return 1;
+      }
+      return 0;
+    }
+
+    @Override
+    public int test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.compare(longVal0, longVal1);
+    }
+  };
+
+  private static final BinaryOp OP_DIV = new BinaryOp("DIV") {
+    @Override
+    public long ref(long longVal0, long longVal1) {
+      return longVal0 / longVal1;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.div(longVal0, longVal1);
+    }
+  };
+
+  private static final BooleanOp OP_EQ = new BooleanOp("EQ") {
+    @Override
+    public boolean ref(long longVal0, long longVal1) {
+      return longVal0 == longVal1;
+    }
+
+    @Override
+    public boolean test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.eq(longVal0, longVal1);
+    }
+  };
+
+  private static final BooleanOp OP_GT = new BooleanOp("GT") {
+    @Override
+    public boolean ref(long longVal0, long longVal1) {
+      return longVal0 > longVal1;
+    }
+
+    @Override
+    public boolean test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.gt(longVal0, longVal1);
+    }
+  };
+
+  private static final BooleanOp OP_GTE = new BooleanOp("GTE") {
+    @Override
+    public boolean ref(long longVal0, long longVal1) {
+      return longVal0 >= longVal1;
+    }
+
+    @Override
+    public boolean test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.gte(longVal0, longVal1);
+    }
+  };
+
+  private static final BooleanOp OP_LT = new BooleanOp("LT") {
+    @Override
+    public boolean ref(long longVal0, long longVal1) {
+      return longVal0 < longVal1;
+    }
+
+    @Override
+    public boolean test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.lt(longVal0, longVal1);
+    }
+  };
+
+  private static final BooleanOp OP_LTE = new BooleanOp("LTE") {
+    @Override
+    public boolean ref(long longVal0, long longVal1) {
+      return longVal0 <= longVal1;
+    }
+
+    @Override
+    public boolean test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.lte(longVal0, longVal1);
+    }
+  };
+
+  private static final BinaryOp OP_MOD = new BinaryOp("MOD") {
+    @Override
+    public long ref(long longVal0, long longVal1) {
+      return longVal0 % longVal1;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.mod(longVal0, longVal1);
+    }
+  };
+
+  private static final BinaryOp OP_MUL = new BinaryOp("MUL") {
+    @Override
+    public long ref(long longVal0, long longVal1) {
+      return longVal0 * longVal1;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.mul(longVal0, longVal1);
+    }
+  };
+
+  private static final UnaryOp OP_NEG = new UnaryOp("NEG") {
+    @Override
+    public long ref(long longVal) {
+      return -longVal;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal) {
+      return LongLib.neg(longVal);
+    }
+  };
+
+  private static final BooleanOp OP_NEQ = new BooleanOp("NEQ") {
+    @Override
+    public boolean ref(long longVal0, long longVal1) {
+      return longVal0 != longVal1;
+    }
+
+    @Override
+    public boolean test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.neq(longVal0, longVal1);
+    }
+  };
+
+  private static final UnaryOp OP_NOT = new UnaryOp("NOT") {
+    @Override
+    public long ref(long longVal) {
+      return ~longVal;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal) {
+      return LongLib.not(longVal);
+    }
+  };
+
+  private static final BinaryOp OP_OR = new BinaryOp("OR") {
+    @Override
+    public long ref(long longVal0, long longVal1) {
+      return longVal0 | longVal1;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.or(longVal0, longVal1);
+    }
+  };
+
+  private static final ShiftOp OP_SHL = new ShiftOp("SHL") {
+    @Override
+    public long ref(long longVal, int shift) {
+      return longVal << shift;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal, int shift) {
+      return LongLib.shl(longVal, shift);
+    }
+  };
+
+  private static final ShiftOp OP_SHR = new ShiftOp("SHR") {
+    @Override
+    public long ref(long longVal, int shift) {
+      return longVal >> shift;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal, int shift) {
+      return LongLib.shr(longVal, shift);
+    }
+  };
+
+  private static final ShiftOp OP_SHRU = new ShiftOp("SHRU") {
+    @Override
+    public long ref(long longVal, int shift) {
+      return longVal >>> shift;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal, int shift) {
+      return LongLib.shru(longVal, shift);
+    }
+  };
+
+  private static final BinaryOp OP_SUB = new BinaryOp("SUB") {
+    @Override
+    public long ref(long longVal0, long longVal1) {
+      return longVal0 - longVal1;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.sub(longVal0, longVal1);
+    }
+  };
+
+  private static final BinaryOp OP_XOR = new BinaryOp("XOR") {
+    @Override
+    public long ref(long longVal0, long longVal1) {
+      return longVal0 ^ longVal1;
+    }
+
+    @Override
+    public LongEmul test(LongEmul longVal0, LongEmul longVal1) {
+      return LongLib.xor(longVal0, longVal1);
+    }
+  };
+
+  private static final Random rand = new Random(1);
+
+  private static final int RANDOM_TESTS = 1000;
+
+  private static long[] TEST_VALUES;
+
+  static {
+    LongLibBase.RUN_IN_JVM = true;
+  }
+
+  static {
+    Set<Long> testSet = new TreeSet<Long>();
+    for (long i = 0; i < BASE_VALUES; i++) {
+      testSet.add(i);
+      testSet.add(-i);
+
+      testSet.add(Long.MIN_VALUE + i);
+      testSet.add(Long.MAX_VALUE - i);
+
+      testSet.add(i << LongLibBase.BITS / 2);
+      testSet.add(i << LongLibBase.BITS);
+      testSet.add(i << (3 * LongLibBase.BITS) / 2);
+      testSet.add(i << 2 * LongLibBase.BITS);
+      testSet.add(i << (5 * LongLibBase.BITS) / 2);
+    }
+
+    for (int i = 0; i < 16; i++) {
+      testSet.add(0x1111111111111111L * i);
+      testSet.add(~(0x1111111111111111L * i));
+      testSet.add(-(0x1111111111111111L * i));
+      testSet.add(0x1010101010101010L * i);
+      testSet.add(~(0x1010101010101010L * i));
+      testSet.add(-(0x1010101010101010L * i));
+      testSet.add(0x0101010101010101L * i);
+      testSet.add(~(0x0101010101010101L * i));
+      testSet.add(-(0x0101010101010101L * i));
+      testSet.add(0x123456789ABCDEFFL * i);
+      testSet.add(~(0x123456789ABCDEFFL * i));
+      testSet.add(-(0x123456789ABCDEFFL * i));
+    }
+
+    for (int i = 0; i < 64; i += 4) {
+      testSet.add(0x1L << i);
+      testSet.add(~(0x1L << i));
+      testSet.add(0x123456789ABCDEFFL >> i);
+      testSet.add(-(0x123456789ABCDEFFL >> i));
+
+      // Powers of two and nearby numbers
+      testSet.add(0x1L << i);
+      for (int j = 1; j <= 16; j++) {
+        testSet.add((0x1L << i) + j);
+        testSet.add(-((0x1L << i) + j));
+        testSet.add(~((0x1L << i) + j));
+        testSet.add((0x1L << i) - j);
+        testSet.add(-((0x1L << i) - j));
+        testSet.add(~((0x1L << i) - j));
+        testSet.add((0x3L << i) + j);
+        testSet.add(-((0x3L << i) + j));
+        testSet.add(~((0x3L << i) + j));
+        testSet.add((0x3L << i) - j);
+        testSet.add(-((0x3L << i) - j));
+        testSet.add(~((0x3L << i) - j));
+      }
+    }
+
+    for (int a = 0; a < 19; a++) {
+      testSet.add((long) Math.pow(10, a));
+    }
+
+    TEST_VALUES = new long[testSet.size()];
+    int index = 0;
+    for (long val : testSet) {
+      TEST_VALUES[index++] = val;
+    }
+
+    System.out.println("VALUES.length = " + index);
+  }
+
+  public static void testAdd() {
+    doTestBinary(OP_ADD);
+  }
+
+  public static void testAnd() {
+    doTestBinary(OP_AND);
+  }
+
+  public static void testCompare() {
+    doTestCompare(OP_COMPARE);
+  }
+
+  public static void testDiv() {
+    doTestBinary(OP_DIV);
+  }
+
+  public static void testEq() {
+    doTestBoolean(OP_EQ);
+  }
+
+  public static void testGetAsIntArray() {
+    long longVal = 0x123456789abcdef0L;
+    int[] array = LongLib.getAsIntArray(longVal);
+    assertEquals(0x12345, array[2]);
+    assertEquals(0x19e26a, array[1]);
+    assertEquals(0x3cdef0, array[0]);
+
+    longVal = -longVal;
+    array = LongLib.getAsIntArray(longVal);
+    assertEquals(0xedcba, array[2]);
+    assertEquals(0x261d95, array[1]);
+    assertEquals(0x32110, array[0]);
+  }
+
+  public static void testGt() {
+    doTestBoolean(OP_GT);
+  }
+
+  public static void testGte() {
+    doTestBoolean(OP_GTE);
+  }
+
+  public static void testLt() {
+    doTestBoolean(OP_LT);
+  }
+
+  public static void testLte() {
+    doTestBoolean(OP_LTE);
+  }
+
+  public static void testMod() {
+    doTestBinary(OP_MOD);
+  }
+
+  public static void testMul() {
+    doTestBinary(OP_MUL);
+  }
+
+  public static void testNeg() {
+    doTestUnary(OP_NEG);
+  }
+
+  public static void testNeq() {
+    doTestBoolean(OP_NEQ);
+  }
+
+  public static void testNot() {
+    doTestUnary(OP_NOT);
+  }
+
+  public static void testNumberOfLeadingZeros() {
+    LongEmul longVal0 = fromLong(0xfedcba9876543210L);
+    for (int i = 0; i <= 64; i++) {
+      assertEquals(i, LongLibBase.numberOfLeadingZeros(longVal0));
+      longVal0 = LongLib.shru(longVal0, 1);
+    }
+  }
+
+  public static void testOr() {
+    doTestBinary(OP_OR);
+  }
+
+  public static void testRoundTrip() {
+    System.out.println("ROUND_TRIP");
+
+    for (int i = 0; i < TEST_VALUES.length + RANDOM_TESTS; i++) {
+      long longVal0 = (i < TEST_VALUES.length) ? TEST_VALUES[i]
+          : rand.nextLong();
+      LongEmul longVal1 = fromLong(longVal0);
+      long l2 = toLong(longVal1);
+      if (longVal0 != l2) {
+        fail("longVal0 = " + longVal0 + ", l2 = " + l2);
+      }
+      if (!toHex(longVal0).equals(toHex(longVal1))) {
+ fail("toHex(longVal0) = " + toHex(longVal0) + ", toHex(longVal1) = "
+            + toHex(longVal1));
+      }
+      if (!toHex(longVal0).equals(toHex(l2))) {
+        fail("toHex(longVal0) = " + toHex(longVal0) + ", toHex(l2) = "
+            + toHex(l2));
+      }
+      if (!LongLib.toString(longVal1).equals(Long.toString(longVal0))) {
+        fail("toString(longVal0) = " + Long.toString(longVal0)
+            + ", toString(longVal1) = " + LongLib.toString(longVal1));
+      }
+    }
+
+    for (int i = 0; i < TEST_VALUES.length + RANDOM_TESTS; i++) {
+      double d0 = (i < TEST_VALUES.length) ? TEST_VALUES[i]
+          : (rand.nextDouble() - 0.5) * 3.0 * Long.MAX_VALUE;
+      long longVal0 = (long) d0;
+      LongEmul longVal1 = LongLib.fromDouble(d0);
+      long l2 = toLong(longVal1);
+      if (longVal0 != l2) {
+        fail("d0 = " + d0 + ", longVal0 = " + longVal0 + ", l2 = " + l2);
+      }
+    }
+
+    for (int i = 0; i < TEST_VALUES.length + RANDOM_TESTS; i++) {
+ long longVal0 = i < TEST_VALUES.length ? TEST_VALUES[i] : rand.nextLong();
+      // Find a round-trip capable value
+      double d0 = longVal0;
+      longVal0 = (long) d0;
+
+      LongEmul longVal1 = fromLong(longVal0);
+      double d1 = LongLib.toDouble(longVal1);
+      LongEmul l2 = LongLib.fromDouble(d1);
+      long l3 = toLong(l2);
+
+      if (longVal0 != l3) {
+        fail("longVal0 = " + longVal0 + ", d1 = " + d1 + ", l3 = " + l3);
+      }
+    }
+
+    for (int i = 0; i < TEST_VALUES.length + RANDOM_TESTS; i++) {
+ int i0 = i < TEST_VALUES.length ? (int) TEST_VALUES[i] : rand.nextInt();
+      long longVal0 = i0;
+      LongEmul longVal1 = LongLib.fromInt(i0);
+      long l2 = toLong(longVal1);
+      if (longVal0 != l2) {
+        fail("i0 = " + i0 + ", longVal0 = " + longVal0 + ", l2 = " + l2);
+      }
+    }
+
+    if (toLong(LongLib.fromDouble(Double.NaN)) != 0) {
+      fail("fromDouble(Nan) != 0");
+    }
+ if (toLong(LongLib.fromDouble(Double.NEGATIVE_INFINITY)) != Long.MIN_VALUE) {
+      fail("fromDouble(-Inf) != MIN_VALUE");
+    }
+ if (toLong(LongLib.fromDouble(Double.POSITIVE_INFINITY)) != Long.MAX_VALUE) {
+      fail("fromDouble(+Inf) != MAX_VALUE");
+    }
+ if (LongLib.toDouble(fromLong(Long.MIN_VALUE)) != -9223372036854775808.0) {
+      fail("toDouble(Long.MIN_VALUE) != -9223372036854775808.0");
+    }
+ if (LongLib.toDouble(fromLong(Long.MAX_VALUE)) != 9223372036854775807.0) {
+      fail("toDouble(Long.MAX_VALUE) != 9223372036854775807.0");
+    }
+  }
+
+  public static void testShl() {
+    doTestShift(OP_SHL);
+  }
+
+  public static void testShr() {
+    doTestShift(OP_SHR);
+  }
+
+  public static void testShru() {
+    doTestShift(OP_SHRU);
+  }
+
+  public static void testSub() {
+    doTestBinary(OP_SUB);
+  }
+
+  public static void testXor() {
+    doTestBinary(OP_XOR);
+  }
+
+  private static LongEmul copy(LongEmul longVal) {
+    LongEmul result = new LongEmul();
+    result.l = longVal.l;
+    result.m = longVal.m;
+    result.h = longVal.h;
+    return result;
+  }
+
+  private static void doTestBinary(BinaryOp op) {
+    System.out.println(op.getName());
+    for (int i = 0; i < TEST_VALUES.length; i++) {
+      long randomLong = rand.nextLong();
+      doTestBinary(op, TEST_VALUES[i], randomLong);
+      doTestBinary(op, randomLong, TEST_VALUES[i]);
+      for (int j = 0; j < TEST_VALUES.length; j++) {
+        doTestBinary(op, TEST_VALUES[i], TEST_VALUES[j]);
+      }
+    }
+    for (int i = 0; i < RANDOM_TESTS; i++) {
+      long longVal0 = rand.nextLong();
+      long longVal1 = rand.nextLong();
+      if (rand.nextInt(20) == 0) {
+        if (rand.nextInt(2) == 0) {
+          longVal1 = longVal0;
+        } else {
+          longVal1 = -longVal0;
+        }
+      }
+      doTestBinary(op, longVal0, longVal1);
+    }
+  }
+
+ private static void doTestBinary(BinaryOp op, long longVal0, long longVal1) {
+    boolean refException = false;
+    long ref = -1;
+    try {
+      ref = op.ref(longVal0, longVal1);
+    } catch (ArithmeticException e) {
+      refException = true;
+    }
+    boolean testException = false;
+    long result = -2;
+    try {
+      LongEmul llongVal0 = fromLong(longVal0);
+      LongEmul llongVal1 = fromLong(longVal1);
+      LongEmul save_llongVal0 = copy(llongVal0);
+      LongEmul save_llongVal1 = copy(llongVal1);
+
+      result = toLong(op.test(llongVal0, llongVal1));
+      if (!LongLib.eq(llongVal0, save_llongVal0)) {
+        System.out.println("Test altered first argument");
+      }
+      if (!LongLib.eq(llongVal1, save_llongVal1)) {
+        System.out.println("Test altered second argument");
+      }
+    } catch (ArithmeticException e) {
+      testException = true;
+    }
+    if (testException && refException) {
+      return;
+    }
+    if (testException != refException) {
+      fail(op.getName() + ": longVal0 = " + longVal0 + ", longVal1 = "
+          + longVal1 + ", testException = " + testException
+          + ", refException = " + refException);
+      return;
+    }
+    if (ref != result) {
+      fail(op.getName() + ": longVal0 = " + longVal0 + ", longVal1 = "
+          + longVal1);
+      toLong(op.test(fromLong(longVal0), fromLong(longVal1)));
+    }
+  }
+
+  private static void doTestBoolean(BooleanOp op) {
+    System.out.println(op.getName());
+    for (int i = 0; i < TEST_VALUES.length; i++) {
+      long randomLong = rand.nextLong();
+      doTestBoolean(op, TEST_VALUES[i], randomLong);
+      doTestBoolean(op, randomLong, TEST_VALUES[i]);
+      for (int j = 0; j < TEST_VALUES.length; j++) {
+        doTestBoolean(op, TEST_VALUES[i], TEST_VALUES[j]);
+      }
+    }
+    for (int i = 0; i < RANDOM_TESTS; i++) {
+      long longVal0 = rand.nextLong();
+      long longVal1 = rand.nextLong();
+      if (rand.nextInt(20) == 0) {
+        if (rand.nextInt(2) == 0) {
+          longVal1 = longVal0;
+        } else {
+          longVal1 = -longVal0;
+        }
+      }
+      doTestBoolean(op, longVal0, longVal1);
+    }
+  }
+
+ private static void doTestBoolean(BooleanOp op, long longVal0, long longVal1) {
+    boolean ref = op.ref(longVal0, longVal1);
+    boolean result = op.test(fromLong(longVal0), fromLong(longVal1));
+    if (ref != result) {
+      fail(op.getName() + ": longVal0 = " + longVal0 + ", longVal1 = "
+          + longVal1);
+    }
+  }
+
+  private static void doTestCompare(CompareOp op) {
+    System.out.println(op.getName());
+    for (int i = 0; i < TEST_VALUES.length; i++) {
+      long randomLong = rand.nextLong();
+      doTestCompare(op, TEST_VALUES[i], randomLong);
+      doTestCompare(op, randomLong, TEST_VALUES[i]);
+      for (int j = 0; j < TEST_VALUES.length; j++) {
+        doTestCompare(op, TEST_VALUES[i], TEST_VALUES[j]);
+      }
+    }
+    for (int i = 0; i < RANDOM_TESTS; i++) {
+      long longVal0 = rand.nextLong();
+      long longVal1 = rand.nextLong();
+      if (rand.nextInt(20) == 0) {
+        if (rand.nextInt(2) == 0) {
+          longVal1 = longVal0;
+        } else {
+          longVal1 = -longVal0;
+        }
+      }
+      doTestCompare(op, longVal0, longVal1);
+    }
+  }
+
+ private static void doTestCompare(CompareOp op, long longVal0, long longVal1) {
+    int ref = op.ref(longVal0, longVal1);
+    int result = op.test(fromLong(longVal0), fromLong(longVal1));
+    if (ref < 0) {
+      ref = -1;
+    } else if (ref > 0) {
+      ref = 1;
+    }
+    if (result < 0) {
+      result = -1;
+    } else if (result > 0) {
+      result = 1;
+    }
+
+    if (ref != result) {
+      fail(op.getName() + ": longVal0 = " + longVal0 + ", longVal1 = "
+          + longVal1 + ", ref = " + ref + ", result = " + result);
+    }
+  }
+
+  private static void doTestShift(ShiftOp op) {
+    System.out.println(op.getName());
+    for (int i = 0; i < TEST_VALUES.length; i++) {
+      for (int shift = -64; shift <= 64; shift++) {
+        doTestShift(op, TEST_VALUES[i], shift);
+      }
+    }
+    for (int i = 0; i < RANDOM_TESTS; i++) {
+      long randomLong = rand.nextLong();
+      for (int shift = -64; shift <= 64; shift++) {
+        doTestShift(op, randomLong, shift);
+      }
+    }
+  }
+
+  private static void doTestShift(ShiftOp op, long longVal, int shift) {
+    long ref = op.ref(longVal, shift);
+    long result = toLong(op.test(fromLong(longVal), shift));
+    if (ref != result) {
+      fail(op.getName() + ": longVal = " + longVal + ", shift = " + shift);
+    }
+  }
+
+  private static void doTestUnary(UnaryOp op) {
+    System.out.println(op.getName());
+    for (int i = 0; i < TEST_VALUES.length; i++) {
+      doTestUnary(op, TEST_VALUES[i]);
+    }
+    for (int i = 0; i < RANDOM_TESTS; i++) {
+      long randomLong = rand.nextLong();
+      doTestUnary(op, randomLong);
+    }
+  }
+
+  private static void doTestUnary(UnaryOp op, long longVal) {
+    long ref = op.ref(longVal);
+    long result = toLong(op.test(fromLong(longVal)));
+    if (ref != result) {
+      fail(op.getName() + ": longVal = " + longVal);
+    }
+  }
+
+  private static LongEmul fromLong(long longVal) {
+    LongEmul result = new LongEmul();
+    result.l = (int) (longVal & LongLibBase.MASK);
+    result.m = (int) ((longVal >> LongLibBase.BITS) & LongLibBase.MASK);
+ result.h = (int) ((longVal >> (2 * LongLibBase.BITS)) & LongLibBase.MASK_2);
+    return result;
+  }
+
+  private static int getBit(LongEmul longVal, int bit) {
+    if (bit < LongLibBase.BITS) {
+      return (longVal.l >> bit) & 0x1;
+    }
+    if (bit < 2 * LongLibBase.BITS) {
+      return (longVal.m >> (bit - LongLibBase.BITS)) & 0x1;
+    }
+    return (longVal.h >> (bit - (2 * LongLibBase.BITS))) & 0x1;
+  }
+
+  private static String toHex(long longVal) {
+    String result = Long.toHexString(longVal);
+    while (result.length() < 16) {
+      result = "0" + result;
+    }
+    return result;
+  }
+
+  private static String toHex(LongEmul longVal) {
+    StringBuilder sb = new StringBuilder();
+    for (int i = 60; i >= 0; i -= 4) {
+      int b0 = getBit(longVal, i);
+      int b1 = getBit(longVal, i + 1);
+      int b2 = getBit(longVal, i + 2);
+      int b3 = getBit(longVal, i + 3);
+      int b = (b3 << 3) + (b2 << 2) + (b1 << 1) + b0;
+      if (b < 10) {
+        sb.append(b);
+      } else {
+        sb.append((char) ('a' + b - 10));
+      }
+    }
+    return sb.toString();
+  }
+
+  private static long toLong(LongEmul longVal) {
+    long b2 = ((long) longVal.h) << (2 * LongLibBase.BITS);
+    long b1 = ((long) longVal.m) << LongLibBase.BITS;
+    return b2 | b1 | longVal.l;
+  }
+
+  public LongLibTest() {
+  }
+}
=======================================
--- /trunk/dev/core/super/com/google/gwt/lang/LongLibBase.java Mon Jun 7 09:38:44 2010 +++ /trunk/dev/core/super/com/google/gwt/lang/LongLibBase.java Mon Jun 14 08:04:23 2010
@@ -18,17 +18,17 @@
 import com.google.gwt.core.client.UnsafeNativeLong;

 final class LongEmul {
-  int l, m, h; // Used only when RUN_IN_JVM is true
-
   public static LongEmul getInstance() {
     return new LongEmul();
   }
+
+  int l, m, h; // Used only when RUN_IN_JVM is true
 }

 /**
  * Implements a Java <code>long</code> in a way that can be translated to
- * JavaScript. Methods that are meant to be called from outside this package
- * are located in {...@link LongLib}.
+ * JavaScript. Methods that are meant to be called from outside this package are
+ * located in {...@link LongLib}.
  */
 class LongLibBase {
   // Force the class to exist
@@ -37,11 +37,11 @@
   /*
* Implementation: A LongEmul containing three values {l, m, h} (low, middle, * high) such that (x.l + ((long) x.m << 22) + ((long) x.h << 44)) is equal to - * the original long integer. The constant 22 is chosen since some browsers + * the original long integer. The constant 22 is chosen since some browsers
    * are faster when operating on integers of 24 bits or less.
    *
-   * By convention, we expect and maintain that the upper bits of each word
-   * be zeroed.
+ * By convention, we expect and maintain that the upper bits of each word be
+   * zeroed.
    *
    * Note that this class must be careful using type "long". Being the
* implementation of the long type for web mode, any place it uses a long is
@@ -49,29 +49,34 @@
    * LongLib#getAsIntArray}.
    */

-  // Note that the 'mul' method implicitly depends on the specific value
-  // BITS == 22
+  // Note that the {...@link LonghLib#mul} method implicitly depends on the
+  // specific value BITS == 22
   protected static final int BITS = 22;
   protected static final int BITS01 = 2 * BITS;
   protected static final int BITS2 = 64 - BITS01;
   protected static final int MASK = (1 << BITS) - 1;
   protected static final int MASK_2 = (1 << BITS2) - 1;
   protected static LongEmul remainder;
-
+
   /**
-   * Allow a standalone Java test such as LongLibJreTest to run this code.
+ * Allow standalone Java tests such as LongLibTest/LongLibJreTest to run this
+   * code.
    */
   protected static boolean RUN_IN_JVM = false;
-
+
   protected static final int SIGN_BIT = BITS2 - 1;
   protected static final int SIGN_BIT_VALUE = 1 << SIGN_BIT;
   protected static final double TWO_PWR_15_DBL = 0x8000;
   protected static final double TWO_PWR_16_DBL = 0x10000;
   protected static final double TWO_PWR_22_DBL = 0x400000;
- protected static final double TWO_PWR_31_DBL = TWO_PWR_16_DBL * TWO_PWR_15_DBL; - protected static final double TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; - protected static final double TWO_PWR_44_DBL = TWO_PWR_22_DBL * TWO_PWR_22_DBL; - protected static final double TWO_PWR_63_DBL = TWO_PWR_32_DBL * TWO_PWR_31_DBL;
+  protected static final double TWO_PWR_31_DBL = TWO_PWR_16_DBL
+      * TWO_PWR_15_DBL;
+  protected static final double TWO_PWR_32_DBL = TWO_PWR_16_DBL
+      * TWO_PWR_16_DBL;
+  protected static final double TWO_PWR_44_DBL = TWO_PWR_22_DBL
+      * TWO_PWR_22_DBL;
+  protected static final double TWO_PWR_63_DBL = TWO_PWR_32_DBL
+      * TWO_PWR_31_DBL;

   /**
    * Web mode implementation; the int array is already the right object.
@@ -80,13 +85,13 @@
   protected static native long asLong(LongEmul value) /*-{
     return value;
   }-*/;
-
+
   protected static LongEmul create(int value) {
     int a0 = value & MASK;
     int a1 = (value >> BITS) & MASK;
     int a2 = (value < 0) ? MASK_2 : 0;

-    if (RUN_IN_JVM ) {
+    if (RUN_IN_JVM) {
       LongEmul a = new LongEmul();
       a.l = a0;
       a.m = a1;
@@ -95,7 +100,7 @@
     }
     return create0(a0, a1, a2);
   }
-
+
   protected static LongEmul create(int a0, int a1, int a2) {
     if (RUN_IN_JVM) {
       LongEmul a = new LongEmul();
@@ -106,8 +111,9 @@
     }
     return create0(a0, a1, a2);
   }
-
- protected static LongEmul divMod(LongEmul a, LongEmul b, boolean computeRemainder) {
+
+  protected static LongEmul divMod(LongEmul a, LongEmul b,
+      boolean computeRemainder) {
     if (isZero(b)) {
       throw new ArithmeticException("divide by zero");
     }
@@ -140,19 +146,18 @@
     boolean aIsMinValue = false;

     /*
-     * Normalize a to a positive value, keeping track of the sign change
-     * in 'negative' (which tracks the sign of both a and b and is used to
-     * determine the sign of the quotient) and 'aIsNegative' (which is used
-     * to determine the sign of the remainder).
+     * Normalize a to a positive value, keeping track of the sign change in
+     * 'negative' (which tracks the sign of both a and b and is used to
+ * determine the sign of the quotient) and 'aIsNegative' (which is used to
+     * determine the sign of the remainder).
      *
-     * For all values of a except MIN_VALUE, we can just negate a and
-     * modify negative and aIsNegative appropriately.  When a == MIN_VALUE,
-     * negation is not possible without overflowing 64 bits, so instead
-     * of computing abs(MIN_VALUE) / abs(b) we compute
-     * (abs(MIN_VALUE) - 1) / abs(b).  The only circumstance under which
-     * these quotients differ is when b is a power of two, which will
-     * divide abs(MIN_VALUE) == 2^64 exactly.  In this case, we can get
-     * the proper result by shifting MIN_VALUE in unsigned fashion.
+ * For all values of a except MIN_VALUE, we can just negate a and modify + * negative and aIsNegative appropriately. When a == MIN_VALUE, negation is
+     * not possible without overflowing 64 bits, so instead of computing
+ * abs(MIN_VALUE) / abs(b) we compute (abs(MIN_VALUE) - 1) / abs(b). The + * only circumstance under which these quotients differ is when b is a power + * of two, which will divide abs(MIN_VALUE) == 2^64 exactly. In this case, + * we can get the proper result by shifting MIN_VALUE in unsigned fashion.
      *
      * We make a single copy of a before the first operation that needs to
      * modify its value.
@@ -186,11 +191,10 @@
     }

     // Now both a and b are non-negative
-
+
     // If b is a power of two, just shift
     if (bpower != -1) {
-      return divModByShift(a, bpower, negative, aIsNegative,
-          computeRemainder);
+ return divModByShift(a, bpower, negative, aIsNegative, computeRemainder);
     }

     // if a < b, the quotient is 0 and the remainder is a
@@ -204,10 +208,10 @@
       }
       return create(); // zero
     }
-
+
     // Generate the quotient using bit-at-a-time long division
-    return divModHelper(aIsCopy ? a : create(a), b, negative,
-        aIsNegative, aIsMinValue, computeRemainder);
+    return divModHelper(aIsCopy ? a : create(a), b, negative, aIsNegative,
+        aIsMinValue, computeRemainder);
   }

   protected static int getH(LongEmul a) {
@@ -273,6 +277,24 @@
   protected static double toDoubleHelper(LongEmul a) {
return getL(a) + (getM(a) * TWO_PWR_22_DBL) + (getH(a) * TWO_PWR_44_DBL);
   }
+
+  /**
+   * Return the number of leading zeros of a long value.
+   */
+  // package-private for testing
+  static int numberOfLeadingZeros(LongEmul a) {
+    int b2 = Integer.numberOfLeadingZeros(getH(a));
+    if (b2 == 32) {
+      int b1 = Integer.numberOfLeadingZeros(getM(a));
+      if (b1 == 32) {
+        return Integer.numberOfLeadingZeros(getL(a)) + 32;
+      } else {
+        return b1 + BITS2 - (32 - BITS);
+      }
+    } else {
+      return b2 - (32 - BITS2);
+    }
+  }

   /**
    * Creates a long instance equal to 0.
@@ -299,7 +321,8 @@
   }

   private static native LongEmul create0(int l, int m, int h) /*-{
- return (a = @com.google.gwt.lang.LongEmul::getInstance()(), a.l = l, a.m = m, a.h = h, a);
+    return (a = @com.google.gwt.lang.LongEmul::getInstance()(),
+        a.l = l, a.m = m, a.h = h, a);
   }-*/;

private static LongEmul divModByMinValue(LongEmul a, boolean computeRemainder) {
@@ -316,7 +339,7 @@
     }
     return create(); // zero
   }
-
+
   private static LongEmul divModByShift(LongEmul a, int bpower,
       boolean negative, boolean aIsNegative, boolean computeRemainder) {
     LongEmul c = LongLib.shr(a, bpower);
@@ -335,8 +358,9 @@
     return c;
   }

- private static LongEmul divModHelper(LongEmul a, LongEmul b, boolean negative,
-      boolean aIsNegative, boolean aIsMinValue, boolean computeRemainder) {
+  private static LongEmul divModHelper(LongEmul a, LongEmul b,
+      boolean negative, boolean aIsNegative, boolean aIsMinValue,
+      boolean computeRemainder) {
     // Align the leading one bits of a and b by shifting b left
     int shift = numberOfLeadingZeros(b) - numberOfLeadingZeros(a);
     LongEmul bshift = LongLib.shl(b, shift);
@@ -407,24 +431,7 @@
   }

   /**
-   * Return the number of leading zeros of a long value.
-   */
-  private static int numberOfLeadingZeros(LongEmul a) {
-    int b2 = Integer.numberOfLeadingZeros(getH(a));
-    if (b2 == 32) {
-      int b1 = Integer.numberOfLeadingZeros(getM(a));
-      if (b1 == 32) {
- return Integer.numberOfLeadingZeros(getL(a)) + BITS2 + 2 * BITS - 32;
-      } else {
-        return b1 + BITS2 - (32 - BITS);
-      }
-    } else {
-      return b2 - (32 - BITS2);
-    }
-  }
-
-  /**
-   * Return the exact log base 2 of a, or -1 if a is not a power of two:
+   * Return the exact log base 2 of a, or -1 if a is not a power of two:
    *
    * <pre>
    * if (x == 2^n) {
@@ -483,15 +490,15 @@
       }
     }
   }
-
+
   private static native void setBitH(LongEmul a, int bit) /*-{
     a.h |= 1 << bit;
   }-*/;
-
+
   private static native void setBitL(LongEmul a, int bit) /*-{
     a.l |= 1 << bit;
   }-*/;
-
+
   private static native void setBitM(LongEmul a, int bit) /*-{
     a.m |= 1 << bit;
   }-*/;
@@ -509,7 +516,7 @@
   }-*/;

   /**
-   * a >>= 1.  Assumes a >= 0.
+   * a >>= 1. Assumes a >= 0.
    */
   private static void toShru1(LongEmul a) {
     int a1 = getM(a);

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to