java/HashValue: add+subtract, remove combineWithValue

Added arithmetic add and subtract operations to HashValue types. Also
removed the obsolete combineWithValue operation that had weird/broken
semantics.
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/HashValue.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/HashValue.java
index 1dd55d5..a656dab 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/HashValue.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/HashValue.java
@@ -17,6 +17,23 @@
      */
     int prefixBits(int numBits);
 
+    /** perform an arithmetic addition of this value and other. Wraps around on
+     * overflow of the defined word size.
+     *
+     * @param other
+     * @return this + other
+     */
+    H add(H other);
+
+    /**
+     * arithmetically substract the given 'other' value from this value.
+     * around on overflow.
+     *
+     * @param other
+     * @return this - other
+     */
+    H subtract(H other);
+
     /** @return the bitwise inverse of this value */
     H inverse();
 
@@ -28,27 +45,4 @@
 
     /** xor this value with another value value of the same type */
     H xor(H other);
-
-    /** calculate a combined hash value of this hash value (the <b>Key</b>) and the hash value
-     *  specified as a parameter (the <b>Value</b>).
-     *  <p>
-     *  The value is constructed as follows:
-     *  <ul>
-     *   <li>the first keyBits bits are taken only from the Key
-     *   <li>the other bits are taken from key xor value.
-     *  </ul>
-     *  The overall result looks like this:
-     *  <pre>
-     *  MSB                      LSB
-     *   +---------+--------------+
-     *   | key     | key ^ value  |
-     *   +---------+--------------+
-     *   |-keyBits-|
-     *  </pre>
-     *
-     * @param value - hash value to be compared with this value (the key)
-     * @param keyBits number of prefix bits that are just taken from key
-     * @return the combined value.
-     */
-    H combineWithValue(H value, int keyBits);
 }
\ No newline at end of file
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U128.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U128.java
index 35ef846..ba7d88a 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U128.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U128.java
@@ -123,15 +123,29 @@
     }
 
     @Override
+    public U128 add(U128 other) {
+        long newRaw2 = this.raw2 + other.raw2;
+        long newRaw1 = this.raw1 + other.raw1;
+        if (UnsignedLongs.compare(newRaw2, this.raw2) < 0 ||
+            UnsignedLongs.compare(newRaw2, other.raw2) < 0) {
+            // raw2 overflow
+            newRaw1+=1;
+        }
+        return U128.of(newRaw1, newRaw2);
+    }
+
+    @Override
+    public U128 subtract(U128 other) {
+        long newRaw2 = this.raw2 - other.raw2;
+        long newRaw1 = this.raw1 - other.raw1;
+        if (UnsignedLongs.compare(this.raw2, other.raw2) < 0) {
+            newRaw1 -= 1;
+        }
+        return U128.of(newRaw1, newRaw2);
+    }
+    @Override
     public int prefixBits(int numBits) {
         return HashValueUtils.prefixBits(this.raw1, numBits);
     }
 
-    @Override
-    public U128 combineWithValue(U128 value, int keyBits) {
-        return U128.of(
-                HashValueUtils.combineWithValue(this.raw1, value.raw1, Math.min(64, keyBits)),
-                HashValueUtils.combineWithValue(this.raw2, value.raw2, Math.max(0,keyBits-64))
-        );
-    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java
index 1353b42..dcd812d 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java
@@ -151,6 +151,16 @@
         return U64.of(raw ^ other.raw);
     }
 
+    @Override
+    public U64 add(U64 other) {
+        return U64.of(this.raw + other.raw);
+    }
+
+    @Override
+    public U64 subtract(U64 other) {
+        return U64.of(this.raw - other.raw);
+    }
+
     /** return the "numBits" highest-order bits of the hash.
      *  @param numBits number of higest-order bits to return [0-32].
      *  @return a numberic value of the 0-32 highest-order bits.
@@ -160,11 +170,6 @@
         return HashValueUtils.prefixBits(raw, numBits);
     }
 
-    @Override
-    public U64 combineWithValue(U64 value, int keyBits) {
-        return U64.of(HashValueUtils.combineWithValue(this.raw, value.raw, keyBits));
-    }
-
     public final static Reader READER = new Reader();
 
     private static class Reader implements OFMessageReader<U64> {
@@ -174,5 +179,4 @@
         }
     }
 
-
 }
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/U128Test.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/U128Test.java
index 18f524e..5393db9 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/U128Test.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/U128Test.java
@@ -9,6 +9,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.text.MessageFormat;
+
 import org.hamcrest.Matchers;
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.jboss.netty.buffer.ChannelBuffers;
@@ -141,6 +143,66 @@
         }
     }
 
+    public static class Triple {
+        U128 a, b, c;
+
+        public Triple(U128 a, U128 b, U128 c) {
+            this.a = a;
+            this.b = b;
+            this.c = c;
+        }
+
+        public static Triple of(U128 a, U128 b, U128 c) {
+            return new Triple(a, b, c);
+        }
+
+        public String msg(String string) {
+            return MessageFormat.format(string, a,b,c);
+        }
+    }
+
+    @Test
+    public void testAddSubtract() {
+        U128 u0_0 = U128.of(0, 0);
+        U128 u0_1 = U128.of(0, 1);
+        U128 u1_0 = U128.of(1, 0);
+        U128 u1_1 = U128.of(1, 1);
+
+        U128 u0_2 = U128.of(0, 2);
+        U128 u2_0 = U128.of(2, 0);
+
+        U128 u0_f = U128.of(0, -1L);
+        U128 uf_0 = U128.of(-1L, 0);
+
+        Triple[] triples = new Triple[] {
+              Triple.of(u0_0, u0_0, u0_0),
+              Triple.of(u0_0, u0_1, u0_1),
+              Triple.of(u0_0, u1_0, u1_0),
+              Triple.of(u0_1, u1_0, u1_1),
+
+              Triple.of(u0_1, u0_1, u0_2),
+              Triple.of(u1_0, u1_0, u2_0),
+
+              Triple.of(u0_1, u0_f, u1_0),
+
+              Triple.of(u0_1, u0_f, u1_0),
+              Triple.of(u0_f, u0_f, U128.of(1, 0xffff_ffff_ffff_fffeL)),
+              Triple.of(uf_0, u0_f, U128.of(-1, -1)),
+              Triple.of(uf_0, u1_0, U128.ZERO),
+
+              Triple.of(U128.of(0x1234_5678_9abc_def1L, 0x1234_5678_9abc_def1L),
+                        U128.of(0xedcb_a987_6543_210eL, 0xedcb_a987_6543_210fL),
+                        U128.ZERO)
+        };
+
+        for(Triple t: triples) {
+            assertThat(t.msg("{0} + {1} = {2}"), t.a.add(t.b), equalTo(t.c));
+            assertThat(t.msg("{1} + {0} = {2}"), t.b.add(t.a), equalTo(t.c));
+
+            assertThat(t.msg("{2} - {0} = {1}"), t.c.subtract(t.a), equalTo(t.b));
+            assertThat(t.msg("{2} - {1} = {0}"), t.c.subtract(t.b), equalTo(t.a));
+        }
+    }
 
     @Test
     public void testCompare() {
@@ -180,21 +242,4 @@
         }
     }
 
-    @Test
-    public void testCombine() {
-        long key = 0x1234567890abcdefL;
-        long val = 0xdeafbeefdeadbeefL;
-        U128 hkey = U128.of(key, key*2);
-        U128 hVal = U128.of(val, val/2);
-
-        assertThat(hkey.combineWithValue(hVal, 0), equalTo(hkey.xor(hVal)));
-        assertThat(hkey.combineWithValue(hVal, 64), equalTo(U128.of(hkey.getMsb(), hkey.getLsb() ^ hVal.getLsb())));
-        assertThat(hkey.combineWithValue(hVal, 128), equalTo(hkey));
-
-        long mask8 = 0xFF00_0000_0000_0000L;
-
-        assertThat(hkey.combineWithValue(hVal, 8), equalTo(U128.of(hkey.getMsb() & mask8 |  hkey.getMsb() ^ hVal.getMsb() & ~mask8,
-                                                                   hkey.getLsb() ^ hVal.getLsb() )));
-    }
-
 }
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/U64Test.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/U64Test.java
index b0cca23..7bd1c46 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/U64Test.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/U64Test.java
@@ -9,6 +9,7 @@
 import static org.junit.Assert.fail;
 
 import java.math.BigInteger;
+import java.text.MessageFormat;
 
 import org.junit.Test;
 
@@ -24,10 +25,10 @@
 
     @Test
     public void testNegativeRaws() {
-        long minus_1 = 0xFFFF_FFFF_FFFF_FFFFL;
-        assertEquals(minus_1, U64.ofRaw(minus_1).getValue());
-        assertEquals(new BigInteger("FFFF_FFFF_FFFF_FFFF".replace("_", ""), 16),  U64.ofRaw(minus_1).getBigInteger());
-        assertEquals(new BigInteger("18446744073709551615"),  U64.ofRaw(minus_1).getBigInteger());
+        long minu1 = 0xFFFF_FFFF_FFFF_FFFFL;
+        assertEquals(minu1, U64.ofRaw(minu1).getValue());
+        assertEquals(new BigInteger("FFFF_FFFF_FFFF_FFFF".replace("_", ""), 16),  U64.ofRaw(minu1).getBigInteger());
+        assertEquals(new BigInteger("18446744073709551615"),  U64.ofRaw(minu1).getBigInteger());
     }
 
     @Test
@@ -62,24 +63,6 @@
     }
 
     @Test
-    public void testCombine() {
-        long key = 0x1234567890abcdefL;
-        long val = 0xdeafbeefdeadbeefL;
-        U64 hkey = U64.of(key);
-        U64 hVal = U64.of(val);
-
-        assertThat(hkey.combineWithValue(hVal, 0), equalTo(hkey.xor(hVal)));
-        assertThat(hkey.combineWithValue(hVal, 64), equalTo(hkey));
-        long mask32 = 0x00000000FFFFFFFFL;
-        assertThat(hkey.combineWithValue(hVal, 32),
-                equalTo(U64.of(key & ~mask32| (key ^ val) & mask32)));
-
-        long tenMask = 0x003FFFFFFFFFFFFFL;
-        assertThat(hkey.combineWithValue(hVal, 10),
-                equalTo(U64.of(key & ~tenMask | (key ^ val) & tenMask)));
-    }
-
-    @Test
     public void testKeyBits() {
         U64 zeroU = U64.of(0);
         assertThat(zeroU.prefixBits(0), equalTo(0));
@@ -105,6 +88,62 @@
         checkInvalidKeyBitSize(signedBitU, 64);
     }
 
+    public static class Triple {
+        U64 a, b, c;
+
+        public Triple(U64 a, U64 b, U64 c) {
+            this.a = a;
+            this.b = b;
+            this.c = c;
+        }
+
+        public static Triple of(U64 a, U64 b, U64 c) {
+            return new Triple(a, b, c);
+        }
+
+        public String msg(String string) {
+            return MessageFormat.format(string, a,b,c);
+        }
+    }
+
+    @Test
+    public void testAddSubtract() {
+        U64 u0 = U64.of(0);
+        U64 u1 = U64.of(1);
+
+        U64 u2 = U64.of(2);
+        U64 u7f = U64.of(0x7fff_ffff_ffff_ffffL);
+        U64 u8 = U64.of(0x8000_0000_0000_0000L);
+
+        U64 uf = U64.of(-1L);
+
+        Triple[] triples = new Triple[] {
+              Triple.of(u0, u0, u0),
+              Triple.of(u0, u1, u1),
+
+              Triple.of(u1, u1, u2),
+
+              Triple.of(u1, uf, u0),
+
+              Triple.of(uf, uf, U64.of(0xffff_ffff_ffff_fffeL)),
+              Triple.of(u0, uf, uf),
+
+              Triple.of(u7f, u1, u8),
+
+              Triple.of(U64.of(0x1234_5678_9abc_def1L),
+                        U64.of(0xedcb_a987_6543_210fL),
+                        U64.ZERO)
+        };
+
+        for(Triple t: triples) {
+            assertThat(t.msg("{0} + {1} = {2}"), t.a.add(t.b), equalTo(t.c));
+            assertThat(t.msg("{1} + {0} = {2}"), t.b.add(t.a), equalTo(t.c));
+
+            assertThat(t.msg("{2} - {0} = {1}"), t.c.subtract(t.a), equalTo(t.b));
+            assertThat(t.msg("{2} - {1} = {0}"), t.c.subtract(t.b), equalTo(t.a));
+        }
+    }
+
     private void
             checkInvalidKeyBitSize(U64 u, int prefixBit) {
         try {