java_gen: implement HashValue protocol
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 f480c47..dd62cd0 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
@@ -24,10 +24,11 @@
 import org.projectfloodlight.openflow.protocol.OFMessageReader;
 import org.projectfloodlight.openflow.protocol.Writeable;
 
+import com.google.common.base.Preconditions;
 import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedLongs;
 
-public class U64 implements Writeable, OFValueType<U64> {
+public class U64 implements Writeable, OFValueType<U64>, HashValue<U64> {
     private static final long UNSIGNED_MASK = 0x7fffffffffffffffL;
     private final static long ZERO_VAL = 0;
     public final static U64 ZERO = new U64(ZERO_VAL);
@@ -110,7 +111,7 @@
 
     @Override
     public U64 applyMask(U64 mask) {
-        return ofRaw(raw & mask.raw);
+        return and(mask);
     }
 
     @Override
@@ -128,6 +129,45 @@
         sink.putLong(raw);
     }
 
+    @Override
+    public U64 inverse() {
+        return U64.of(~raw);
+    }
+
+    @Override
+    public U64 or(U64 other) {
+        return U64.of(raw | other.raw);
+    }
+
+    @Override
+    public U64 and(U64 other) {
+        return ofRaw(raw & other.raw);
+    }
+    @Override
+    public U64 xor(U64 other) {
+        return U64.of(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.
+     */
+    @Override
+    public int prefixBits(int numBits) {
+        Preconditions.checkArgument(numBits >= 0 && numBits < 32,
+                "numBits must be in range [0, 32[");
+
+        final int mask = (1 << numBits) -1;
+        final int shiftDown = 64 - numBits;
+
+        return (int) ((raw >>> shiftDown) & mask);
+    }
+
+    @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> {
@@ -136,4 +176,6 @@
             return U64.ofRaw(bb.readLong());
         }
     }
+
+
 }
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 e45e8a0..a979fab 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
@@ -1,6 +1,11 @@
 package org.projectfloodlight.openflow.types;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 
 import java.math.BigInteger;
 
@@ -18,9 +23,59 @@
 
     @Test
     public void testNegativeRaws() {
-        long minus_1 = 0xFFffFFffFFffFFffL;
+        long minus_1 = 0xFFFF_FFFF_FFFF_FFFFL;
         assertEquals(minus_1, U64.ofRaw(minus_1).getValue());
-        assertEquals(new BigInteger("FFffFFffFFffFFff", 16),  U64.ofRaw(minus_1).getBigInteger());
+        assertEquals(new BigInteger("FFFF_FFFF_FFFF_FFFF".replace("_", ""), 16),  U64.ofRaw(minus_1).getBigInteger());
         assertEquals(new BigInteger("18446744073709551615"),  U64.ofRaw(minus_1).getBigInteger());
     }
+
+    @Test
+    public void testEqualHashCode() {
+        U64 h1 = U64.of(0xdeafbeefdeadbeefL);
+        U64 h2 = U64.of(0xdeafbeefdeadbeefL);
+        U64 h3 = U64.of(0xeeafbeefdeadbeefL);
+
+        assertTrue(h1.equals(h1));
+        assertTrue(h1.equals(h2));
+        assertFalse(h1.equals(h3));
+        assertTrue(h2.equals(h1));
+
+        assertEquals(h1.hashCode(), h2.hashCode());
+        assertNotEquals(h1.hashCode(), h3.hashCode()); // not technically a requirement, but we'll hopefully be lucky.
+    }
+
+    @Test
+    public void testXor() {
+        U64 hNull = U64.of(0);
+        U64 hDeadBeef = U64.of(0xdeafbeefdeadbeefL);
+        assertThat(hNull.xor(hNull), equalTo(hNull));
+        assertThat(hNull.xor(hDeadBeef), equalTo(hDeadBeef));
+        assertThat(hDeadBeef.xor(hNull), equalTo(hDeadBeef));
+        assertThat(hDeadBeef.xor(hDeadBeef), equalTo(hNull));
+
+
+        U64 h1 = U64.of(1L);
+        U64 h8 = U64.of(0x8000000000000000L);
+        U64 h81 = U64.of(0x8000000000000001L);
+        assertThat(h1.xor(h8), equalTo(h81));
+    }
+
+    @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)));
+    }
+
 }