Bump MRI upstreams
[openflowplugin.git] / extension / openflowjava-extension-nicira / src / main / java / org / opendaylight / openflowjava / nx / codec / match / NxmHeader.java
index 394ef58ff787a2d9b305f6786c56a44c91f792bb..e1e0d7ad28cb4f8745d4d7b3b7ea0ff449530961 100644 (file)
-/**
+/*
  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- * 
+ *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 package org.opendaylight.openflowjava.nx.codec.match;
 
-import com.google.common.primitives.Ints;
+import com.google.common.base.MoreObjects;
+import java.math.BigInteger;
+import java.util.Objects;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.yangtools.yang.common.Uint64;
 
 /**
- * @author msunal
+ * Nxm header.
  *
+ * @author msunal
  */
-public class NxmHeader {
+public final class NxmHeader {
 
+    // Full 4 or 8 byte header as big integer
+    private final Uint64 header;
+    // Full 4 or 8 byte header as long
     private final long headerAsLong;
+    // 4 byte class, field, length as long
+    private final long shortHeader;
     private final int oxmClass;
     private final int nxmField;
     private final boolean hasMask;
     private final int length;
+    private final long experimenterId;
+
+    /**
+     * Builds a {@code NxmHeader} from a {@code BigInteger} representation,
+     * that is, one for which {@link BigInteger#longValue()} produces
+     * a valid long representation.
+     *
+     * @param header the header as {@code BigInteger}.
+     * @see NxmHeader#NxmHeader(long)
+     */
+    public NxmHeader(final Uint64 header) {
+        headerAsLong = header.longValue();
+        if (isExperimenter(header)) {
+            experimenterId = (int) headerAsLong;
+            shortHeader = headerAsLong >>> 32;
+        } else {
+            shortHeader = headerAsLong;
+            experimenterId = -1;
+        }
+
+        this.header = header;
+        try {
+            oxmClass = Math.toIntExact(extractSub(shortHeader, 16, 16));
+            nxmField = Math.toIntExact(extractSub(shortHeader, 7, 9));
+            hasMask = extractSub(shortHeader, 1, 8) == 1;
+            length = Math.toIntExact(extractSub(shortHeader, 8, 0));
+        } catch (ArithmeticException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    /**
+     * Builds a {@code NxmHeader} from a {@code long} representation.
+     * For non experimenter, the 4 byte header are the least
+     * significant of the long, being the other 4 most significant
+     * bytes 0. For experimenter, the full 8 byte constitute the header,
+     * being the 4 least significant the experimenter id.
+     *
+     * @param header the header as a {@code long}.
+     */
+    public NxmHeader(final long header) {
+        this(Uint64.fromLongBits(header));
+    }
+
+    /**
+     * Build a non experimenter header from it's constituent fields.
+     *
+     * @param oxmClass the OXM class.
+     * @param nxmField the NXM field.
+     * @param hasMask the hasMask field.
+     * @param length the length field.
+     */
+    public NxmHeader(final int oxmClass, final int nxmField, final boolean hasMask, final int length) {
+        this(oxmClass, nxmField, hasMask, length, -1);
+    }
 
-    public NxmHeader(long header) {
-        this.headerAsLong = header;
-        this.oxmClass = Ints.checkedCast(extractSub(header, 16, 16));
-        this.nxmField = Ints.checkedCast(extractSub(header, 7, 9));
-        this.hasMask = extractSub(header, 1, 8) == 1 ? true : false;
-        this.length = Ints.checkedCast(extractSub(header, 8, 0));
+    /**
+     * Build a experimenter header from it's constituent fields.
+     * The OXM class will be set to 0xFFFF.
+     *
+     * @param nxmField the NXM field.
+     * @param hasMask the hasMask field.
+     * @param length the length field.
+     * @param experimenterId the esperimenter id field.
+     */
+    public NxmHeader(final int nxmField, final boolean hasMask, final int length, final long experimenterId) {
+        this(EncodeConstants.EXPERIMENTER_VALUE, nxmField, hasMask, length, experimenterId);
     }
 
-    public NxmHeader(int oxmClass, int nxmField, boolean hasMask, int length) {
+    private NxmHeader(final int oxmClass, final int nxmField, final boolean hasMask, final int length,
+            final long experimenterId) {
         this.oxmClass = oxmClass;
         this.nxmField = nxmField;
         this.hasMask = hasMask;
         this.length = length;
-        this.headerAsLong = ((((long) oxmClass) << 16) | (nxmField << 9) | ((hasMask ? 1 : 0) << 8) | (length));
+        shortHeader = (long) oxmClass << 16 | nxmField << 9 | (hasMask ? 1 : 0) << 8 | length;
+        this.experimenterId = experimenterId;
+        if (isExperimenter()) {
+            header = Uint64.fromLongBits((shortHeader << 32) + experimenterId);
+        } else {
+            header = Uint64.valueOf(shortHeader);
+        }
+        headerAsLong = header.longValue();
     }
 
-    private static long extractSub(final long l, final int nrBits, final int offset) {
-        final long rightShifted = l >>> offset;
+    private static long extractSub(final long value, final int nrBits, final int offset) {
+        final long rightShifted = value >>> offset;
         final long mask = (1L << nrBits) - 1L;
         return rightShifted & mask;
     }
 
+    /**
+     * Returns the {@code Uint64} representation of the header.
+     *
+     * @return the header.
+     * @see NxmHeader#NxmHeader(Uint64)
+     */
+    public Uint64 toUint64() {
+        return header;
+    }
+
+    /**
+     * Returns the {@code long} representation of the header.
+     *
+     * @return the header.
+     * @see NxmHeader#NxmHeader(long)
+     */
     public long toLong() {
         return headerAsLong;
     }
@@ -63,16 +157,25 @@ public class NxmHeader {
         return length;
     }
 
+    public long getExperimenterId() {
+        return experimenterId;
+    }
+
+    public boolean isExperimenter() {
+        return oxmClass == EncodeConstants.EXPERIMENTER_VALUE;
+    }
+
+    public static boolean isExperimenter(final Uint64 uint) {
+        return uint.longValue() >>> 48 == EncodeConstants.EXPERIMENTER_VALUE;
+    }
+
     @Override
     public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + (int) (headerAsLong ^ (headerAsLong >>> 32));
-        return result;
+        return Objects.hash(shortHeader, experimenterId);
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(final Object obj) {
         if (this == obj) {
             return true;
         }
@@ -83,16 +186,21 @@ public class NxmHeader {
             return false;
         }
         NxmHeader other = (NxmHeader) obj;
-        if (headerAsLong != other.headerAsLong) {
-            return false;
-        }
-        return true;
+        return shortHeader == other.shortHeader
+                && experimenterId == other.experimenterId;
     }
 
     @Override
     public String toString() {
-        return "NxmHeader [headerAsLong=" + headerAsLong + ", oxmClass=" + oxmClass + ", nxmField=" + nxmField
-                + ", hasMask=" + hasMask + ", length=" + length + "]";
+        return MoreObjects.toStringHelper(this)
+                .add("header", header)
+                .add("headerAsLong", headerAsLong)
+                .add("shortHeader", shortHeader)
+                .add("oxmClass", oxmClass)
+                .add("oxmField", nxmField)
+                .add("hasMask", hasMask)
+                .add("length", length)
+                .add("experimenterId", experimenterId)
+                .toString();
     }
-
 }