Merge into master from pull request #220:
add bitwise logical operators and broadcast check (https://github.com/floodlight/loxigen/pull/220)
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
index c96be83..d9993b0 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddress.java
@@ -20,6 +20,33 @@
      */
     public abstract int asCidrMaskLength();
 
+    /**
+     * Checks if the IPAddress is the global broadcast address
+     * 255.255.255.255 in case of IPv4
+     * @return boolean true or false
+     */
+    public abstract boolean isBroadcast();
+
+    /**
+     * Perform a low level AND operation on the bits of two IPAddress<?> objects
+     * @param   IPAddress<?> other
+     * @return  new IPAddress<?> object after the AND oper
+     */
+    public abstract F and(F other);
+
+    /**
+     * Perform a low level OR operation on the bits of two IPAddress<?> objects
+     * @param   IPAddress<?> other
+     * @return  new IPAddress<?> object after the AND oper
+     */
+    public abstract F or(F other);
+
+    /**
+     * Returns a new IPAddress object with the bits inverted
+     * @return  IPAddress<?>
+     */
+    public abstract F not();
+
     @Override
     public abstract boolean equals(Object other);
 
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java
index 2087ab4..ba7eb93 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPAddressWithMask.java
@@ -9,6 +9,18 @@
 
     public abstract IPVersion getIpVersion();
 
+    public F getSubnetBroadcastAddress() {
+        if (!mask.isCidrMask()) {
+            throw new IllegalArgumentException("Mask Invalid " + mask +
+                                               " cannot get subnet for non CIDR mask");
+        }
+        return value.or(mask.not());
+    }
+
+    public boolean isSubnetBroadcastAddress(F candidate) {
+        return getSubnetBroadcastAddress().equals(candidate);
+    }
+
     public static IPAddressWithMask<?> of(String ip) {
         if (ip == null) {
             throw new NullPointerException("String ip must not be null");
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
index 43a7a17..43fefac 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
@@ -69,6 +69,34 @@
         }
     }
 
+    @Override
+    public boolean isBroadcast() {
+        return this.equals(NO_MASK);
+    }
+
+    @Override
+    public IPv4Address and(IPv4Address other) {
+        if (other == null) {
+            throw new NullPointerException("Other IP Address must not be null");
+        }
+        IPv4Address otherIp = (IPv4Address) other;
+        return IPv4Address.of(rawValue & otherIp.rawValue);
+    }
+
+    @Override
+    public IPv4Address or(IPv4Address other) {
+        if (other == null) {
+            throw new NullPointerException("Other IP Address must not be null");
+        }
+        IPv4Address otherIp = (IPv4Address) other;
+        return IPv4Address.of(rawValue | otherIp.rawValue);
+    }
+
+    @Override
+    public IPv4Address not() {
+        return IPv4Address.of(~rawValue);
+    }
+
     public static IPv4Address of(final byte[] address) {
         if (address == null) {
             throw new NullPointerException("Address must not be null");
@@ -163,7 +191,7 @@
 
     @Override
     public IPv4Address applyMask(IPv4Address mask) {
-        return IPv4Address.of(this.rawValue & mask.rawValue);
+        return and(mask);
     }
 
     @Override
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
index c9dea13..1ee9e89 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
@@ -93,6 +93,34 @@
         }
     }
 
+    @Override
+    public boolean isBroadcast() {
+        return this.equals(NO_MASK);
+    }
+
+    @Override
+    public IPv6Address and(IPv6Address other) {
+        if (other == null) {
+            throw new NullPointerException("Other IP Address must not be null");
+        }
+        IPv6Address otherIp = (IPv6Address) other;
+        return IPv6Address.of((raw1 & otherIp.raw1), (raw2 & otherIp.raw2));
+    }
+
+    @Override
+    public IPv6Address or(IPv6Address other) {
+        if (other == null) {
+            throw new NullPointerException("Other IP Address must not be null");
+        }
+        IPv6Address otherIp = (IPv6Address) other;
+        return IPv6Address.of((raw1 | otherIp.raw1), (raw2 | otherIp.raw2));
+    }
+
+    @Override
+    public IPv6Address not() {
+        return IPv6Address.of(~raw1, ~raw2);
+    }
+
     public static IPv6Address of(final byte[] address) {
         if (address == null) {
             throw new NullPointerException("Address must not be null");
@@ -361,7 +389,7 @@
 
     @Override
     public IPv6Address applyMask(IPv6Address mask) {
-        return IPv6Address.of(this.raw1 & mask.raw1, this.raw2 & mask.raw2);
+        return and(mask);
     }
 
     @Override
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
index 334ec0d..a57b42a 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv4AddressTest.java
@@ -104,6 +104,29 @@
     };
 
     @Test
+    public void testLogicalOperatorsBroadcast() {
+        assertTrue(IPv4Address.NO_MASK.not().equals(IPv4Address.FULL_MASK));
+        assertTrue(IPv4Address.NO_MASK.or(IPv4Address.FULL_MASK).
+                   equals(IPv4Address.NO_MASK));
+        assertTrue(IPv4Address.NO_MASK.and(IPv4Address.FULL_MASK).
+                   equals(IPv4Address.FULL_MASK));
+
+        assertTrue(IPv4Address.NO_MASK.isBroadcast());
+        assertTrue(!IPv4Address.FULL_MASK.isBroadcast());
+    }
+
+    @Test
+    public void testMaskedSubnetBroadcast() {
+        assertTrue(IPv4AddressWithMask.of("10.10.10.1/24")
+                   .getSubnetBroadcastAddress()
+                   .equals(IPv4Address.of("10.10.10.255")));
+        assertTrue(IPv4AddressWithMask.of("10.10.10.1/24")
+                   .isSubnetBroadcastAddress(IPv4Address.of("10.10.10.255")));
+        assertTrue(!IPv4AddressWithMask.of("10.10.10.1/24")
+                   .isSubnetBroadcastAddress(IPv4Address.of("10.10.10.254")));
+    }
+
+    @Test
     public void testMaskedMatchesCidr() {
         IPv4AddressWithMask slash28 = IPv4AddressWithMask.of("10.0.42.16/28");
 
@@ -336,5 +359,13 @@
         } catch (NullPointerException e) {
             assertNotNull(e.getMessage());
         }
+        try {
+            IPv4AddressWithMask.of(IPv4Address.of("10.10.10.0"),
+                                   IPv4Address.of("255.0.255.0"))
+                                   .getSubnetBroadcastAddress();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            assertNotNull(e.getMessage());
+        }
     }
 }
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
index c521292..6963c21 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/IPv6AddressTest.java
@@ -76,6 +76,29 @@
     };
 
     @Test
+    public void testLogicalOperatorsBroadcast() {
+        assertTrue(IPv6Address.NO_MASK.not().equals(IPv6Address.FULL_MASK));
+        assertTrue(IPv6Address.NO_MASK.or(IPv6Address.FULL_MASK).
+                   equals(IPv6Address.NO_MASK));
+        assertTrue(IPv6Address.NO_MASK.and(IPv6Address.FULL_MASK).
+                   equals(IPv6Address.FULL_MASK));
+
+        assertTrue(IPv6Address.NO_MASK.isBroadcast());
+        assertTrue(!IPv6Address.FULL_MASK.isBroadcast());
+    }
+
+    @Test
+    public void testMaskedSubnetBroadcast() {
+        assertTrue(IPv6AddressWithMask.of("10:10::1/112")
+                   .getSubnetBroadcastAddress()
+                   .equals(IPv6Address.of("10:10::ffff")));
+        assertTrue(IPv6AddressWithMask.of("10:10::1/112")
+                   .isSubnetBroadcastAddress(IPv6Address.of("10:10::ffff")));
+        assertTrue(!IPv6AddressWithMask.of("10:10::1/112")
+                   .isSubnetBroadcastAddress(IPv6Address.of("10:10::fffd")));
+    }
+
+    @Test
     public void testConstants() {
         byte[] zeros = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
                          (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
@@ -282,5 +305,13 @@
         } catch (NullPointerException e) {
             assertNotNull(e.getMessage());
         }
+        try {
+            IPv6AddressWithMask.of(IPv6Address.of("10:10::0"),
+                                   IPv6Address.of("ffff:0:ffff::"))
+                                   .getSubnetBroadcastAddress();
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            assertNotNull(e.getMessage());
+        }
     }
 }