Support for bitwise AND/OR/XOR in ImmutableByteSequence
Also, minor refactoring of the fit() method to improve code readability
Change-Id: I826650c3fc45573c723d9d2dd8692da174d9ae08
diff --git a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java
index c90ea35..47df7f1 100644
--- a/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java
+++ b/apps/p4-tutorial/pipeconf/src/main/java/org/onosproject/p4tutorial/pipeconf/PipelineInterpreterImpl.java
@@ -54,7 +54,6 @@
import static java.lang.String.format;
import static java.util.stream.Collectors.toList;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
import static org.onosproject.net.PortNumber.CONTROLLER;
import static org.onosproject.net.PortNumber.FLOOD;
import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
@@ -219,7 +218,7 @@
try {
return PiControlMetadata.builder()
.withId(PiControlMetadataId.of(EGRESS_PORT))
- .withValue(fit(copyFrom(portNumber), PORT_FIELD_BITWIDTH))
+ .withValue(copyFrom(portNumber).fit(PORT_FIELD_BITWIDTH))
.build();
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
throw new PiInterpreterException(format("Port number %d too big, %s", portNumber, e.getMessage()));
diff --git a/apps/p4runtime-test/src/test/java/org/onosproject/p4runtime/test/P4RuntimeTest.java b/apps/p4runtime-test/src/test/java/org/onosproject/p4runtime/test/P4RuntimeTest.java
index 319afec..6c320ad 100644
--- a/apps/p4runtime-test/src/test/java/org/onosproject/p4runtime/test/P4RuntimeTest.java
+++ b/apps/p4runtime-test/src/test/java/org/onosproject/p4runtime/test/P4RuntimeTest.java
@@ -58,7 +58,6 @@
import java.util.concurrent.ExecutionException;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
import static org.onlab.util.ImmutableByteSequence.ofZeros;
import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.BMV2_JSON;
@@ -98,7 +97,7 @@
.usePlaintext(true);
private P4RuntimeClientImpl client;
- private final ImmutableByteSequence ethAddr = fit(copyFrom(1), 48);
+ private final ImmutableByteSequence ethAddr = copyFrom(1).fit(48);
private final ImmutableByteSequence portValue = copyFrom((short) 1);
private final PiMatchFieldId ethDstAddrFieldId = PiMatchFieldId.of(ETHERNET + DOT + DST_ADDR);
private final PiMatchFieldId ethSrcAddrFieldId = PiMatchFieldId.of(ETHERNET + DOT + SRC_ADDR);
@@ -198,11 +197,11 @@
InterruptedException, ImmutableByteSequence.ByteSequenceTrimException {
PiPacketOperation packetOperation = PiPacketOperation.builder()
- .withData(fit(copyFrom(1), 48 + 48 + 16))
+ .withData(copyFrom(1).fit(48 + 48 + 16))
.withType(PACKET_OUT)
.withMetadata(PiControlMetadata.builder()
.withId(PiControlMetadataId.of("egress_port"))
- .withValue(fit(copyFrom(255), 9))
+ .withValue(copyFrom(255).fit(9))
.build())
.build();
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/AbstractCriterionTranslator.java b/core/net/src/main/java/org/onosproject/net/pi/impl/AbstractCriterionTranslator.java
index 36e9068..9b2b4a0 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/AbstractCriterionTranslator.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/AbstractCriterionTranslator.java
@@ -23,7 +23,6 @@
import java.util.Optional;
import static org.onlab.util.ImmutableByteSequence.ByteSequenceTrimException;
-import static org.onlab.util.ImmutableByteSequence.fit;
/**
* Abstract implementation of a criterion translator that opportunistically tries to generate different types of match
@@ -48,7 +47,7 @@
void initAsExactMatch(ImmutableByteSequence value, int bitWidth)
throws ByteSequenceTrimException {
this.initType = PiMatchType.EXACT;
- this.value = fit(value, bitWidth);
+ this.value = value.fit(bitWidth);
this.bitWidth = bitWidth;
}
@@ -63,8 +62,8 @@
void initAsTernaryMatch(ImmutableByteSequence value, ImmutableByteSequence mask, int bitWidth)
throws ByteSequenceTrimException {
this.initType = PiMatchType.TERNARY;
- this.value = fit(value, bitWidth);
- this.mask = fit(mask, bitWidth);
+ this.value = value.fit(bitWidth);
+ this.mask = mask.fit(bitWidth);
this.bitWidth = bitWidth;
}
@@ -79,7 +78,7 @@
void initAsLpm(ImmutableByteSequence value, int prefixLength, int bitWidth)
throws ByteSequenceTrimException {
this.initType = PiMatchType.LPM;
- this.value = fit(value, bitWidth);
+ this.value = value.fit(bitWidth);
this.prefixLength = prefixLength;
this.bitWidth = bitWidth;
}
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java
index b4ce830..85c763c 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiFlowRuleTranslatorImpl.java
@@ -59,7 +59,6 @@
import static java.lang.String.format;
import static org.onlab.util.ImmutableByteSequence.ByteSequenceTrimException;
-import static org.onlab.util.ImmutableByteSequence.fit;
import static org.onosproject.net.flow.criteria.Criterion.Type.PROTOCOL_INDEPENDENT;
import static org.onosproject.net.pi.impl.CriterionTranslatorHelper.translateCriterion;
import static org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull;
@@ -247,7 +246,7 @@
"Not such parameter '%s' for action '%s'", param.id(), actionModel)));
try {
newActionBuilder.withParameter(new PiActionParam(param.id(),
- fit(param.value(), paramModel.bitWidth())));
+ param.value().fit(paramModel.bitWidth())));
} catch (ByteSequenceTrimException e) {
throw new PiTranslationException(format(
"Size mismatch for parameter '%s' of action '%s': %s",
@@ -413,11 +412,11 @@
switch (fieldModel.matchType()) {
case EXACT:
return new PiExactFieldMatch(fieldMatch.fieldId(),
- fit(((PiExactFieldMatch) fieldMatch).value(), modelBitWidth));
+ ((PiExactFieldMatch) fieldMatch).value().fit(modelBitWidth));
case TERNARY:
return new PiTernaryFieldMatch(fieldMatch.fieldId(),
- fit(((PiTernaryFieldMatch) fieldMatch).value(), modelBitWidth),
- fit(((PiTernaryFieldMatch) fieldMatch).mask(), modelBitWidth));
+ ((PiTernaryFieldMatch) fieldMatch).value().fit(modelBitWidth),
+ ((PiTernaryFieldMatch) fieldMatch).mask().fit(modelBitWidth));
case LPM:
PiLpmFieldMatch lpmfield = (PiLpmFieldMatch) fieldMatch;
if (lpmfield.prefixLength() > modelBitWidth) {
@@ -426,12 +425,12 @@
fieldMatch.fieldId(), lpmfield.prefixLength(), modelBitWidth));
}
return new PiLpmFieldMatch(fieldMatch.fieldId(),
- fit(lpmfield.value(), modelBitWidth),
+ lpmfield.value().fit(modelBitWidth),
lpmfield.prefixLength());
case RANGE:
return new PiRangeFieldMatch(fieldMatch.fieldId(),
- fit(((PiRangeFieldMatch) fieldMatch).lowValue(), modelBitWidth),
- fit(((PiRangeFieldMatch) fieldMatch).highValue(), modelBitWidth));
+ ((PiRangeFieldMatch) fieldMatch).lowValue().fit(modelBitWidth),
+ ((PiRangeFieldMatch) fieldMatch).highValue().fit(modelBitWidth));
case VALID:
return fieldMatch;
default:
diff --git a/core/net/src/test/java/org/onosproject/net/pi/impl/PiTranslatorServiceTest.java b/core/net/src/test/java/org/onosproject/net/pi/impl/PiTranslatorServiceTest.java
index 1d0caee..9af6745 100644
--- a/core/net/src/test/java/org/onosproject/net/pi/impl/PiTranslatorServiceTest.java
+++ b/core/net/src/test/java/org/onosproject/net/pi/impl/PiTranslatorServiceTest.java
@@ -65,7 +65,6 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
import static org.onosproject.net.group.GroupDescription.Type.SELECT;
import static org.onosproject.pipelines.basic.BasicConstants.ACT_PRF_WCMP_SELECTOR_ID;
import static org.onosproject.pipelines.basic.BasicConstants.ACT_PRM_PORT_ID;
@@ -237,7 +236,7 @@
private static PiActionGroupMember outputMember(int portNum)
throws ImmutableByteSequence.ByteSequenceTrimException {
- PiActionParam param = new PiActionParam(ACT_PRM_PORT_ID, fit(copyFrom(portNum), PORT_BITWIDTH));
+ PiActionParam param = new PiActionParam(ACT_PRM_PORT_ID, copyFrom(portNum).fit(PORT_BITWIDTH));
PiAction piAction = PiAction.builder()
.withId(ACT_SET_EGRESS_PORT_ID)
.withParameter(param).build();
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicInterpreterImpl.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicInterpreterImpl.java
index 8e7b399..5ff38ba 100644
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicInterpreterImpl.java
+++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicInterpreterImpl.java
@@ -49,7 +49,6 @@
import static java.lang.String.format;
import static java.util.stream.Collectors.toList;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
import static org.onosproject.net.PortNumber.CONTROLLER;
import static org.onosproject.net.PortNumber.FLOOD;
import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
@@ -130,7 +129,7 @@
return PiAction.builder()
.withId(ACT_SET_EGRESS_PORT_ID)
.withParameter(new PiActionParam(ACT_PRM_PORT_ID,
- fit(copyFrom(port.toLong()), PORT_BITWIDTH)))
+ copyFrom(port.toLong()).fit(PORT_BITWIDTH)))
.build();
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
throw new PiInterpreterException(e.getMessage());
@@ -231,7 +230,7 @@
try {
return PiControlMetadata.builder()
.withId(PKT_META_EGRESS_PORT_ID)
- .withValue(fit(copyFrom(portNumber), PORT_BITWIDTH))
+ .withValue(copyFrom(portNumber).fit(PORT_BITWIDTH))
.build();
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
throw new PiInterpreterException(format(
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java
index 29e3a48..e79cd44 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricInterpreter.java
@@ -53,7 +53,6 @@
import static java.lang.String.format;
import static java.util.stream.Collectors.toList;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
import static org.onosproject.net.PortNumber.FLOOD;
import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
@@ -208,7 +207,7 @@
try {
return PiControlMetadata.builder()
.withId(FabricConstants.CTRL_META_EGRESS_PORT_ID)
- .withValue(fit(copyFrom(portNumber), FabricConstants.PORT_BITWIDTH))
+ .withValue(copyFrom(portNumber).fit(FabricConstants.PORT_BITWIDTH))
.build();
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
throw new PiInterpreterException(format(
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
index 6346302..00c4047 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
@@ -250,7 +250,7 @@
MplsLabel mplsLabel = modMplsInst.label();
try {
ImmutableByteSequence mplsValue =
- ImmutableByteSequence.fit(ImmutableByteSequence.copyFrom(mplsLabel.toInt()), 20);
+ ImmutableByteSequence.copyFrom(mplsLabel.toInt()).fit(20);
PiActionParam mplsParam = new PiActionParam(FabricConstants.ACT_PRM_LABEL_ID, mplsValue);
return PiAction.builder()
// FIXME: fins a way to determine v4 or v6
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java
index 8d97f20..c60a5e8 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java
@@ -233,7 +233,7 @@
PiActionParam portParam = new PiActionParam(FabricConstants.ACT_PRM_PORT_NUM_ID,
ImmutableByteSequence.copyFrom(portNumVal));
ImmutableByteSequence mplsVal =
- ImmutableByteSequence.fit(ImmutableByteSequence.copyFrom(MPLS_10.toInt()), 20);
+ ImmutableByteSequence.copyFrom(MPLS_10.toInt()).fit(20);
PiActionParam mplsParam = new PiActionParam(FabricConstants.ACT_PRM_LABEL_ID, mplsVal);
PiAction expectedAction = PiAction.builder()
.withId(FabricConstants.ACT_NEXT_MPLS_ROUTING_V4_ID)
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/DefaultPacketInTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/DefaultPacketInTest.java
index 38fcf6d..5993142 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/DefaultPacketInTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/DefaultPacketInTest.java
@@ -21,14 +21,13 @@
import org.junit.Test;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.pi.runtime.PiControlMetadata;
import org.onosproject.net.pi.model.PiControlMetadataId;
+import org.onosproject.net.pi.runtime.PiControlMetadata;
import org.onosproject.net.pi.runtime.PiPacketOperation;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
-import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_IN;
+import static org.onosproject.net.pi.model.PiPacketOperationType.PACKET_OUT;
/**
* Test for DefaultPacketIn class.
@@ -65,7 +64,7 @@
.withType(PACKET_OUT)
.withMetadata(PiControlMetadata.builder()
.withId(PiControlMetadataId.of("egress_port"))
- .withValue(fit(copyFrom(DEFAULT_ORIGINAL_VALUE), DEFAULT_BIT_WIDTH))
+ .withValue(copyFrom(DEFAULT_ORIGINAL_VALUE).fit(DEFAULT_BIT_WIDTH))
.build())
.build();
@@ -75,7 +74,7 @@
.withType(PACKET_IN)
.withMetadata(PiControlMetadata.builder()
.withId(PiControlMetadataId.of("ingress_port"))
- .withValue(fit(copyFrom(DEFAULT_ORIGINAL_VALUE), DEFAULT_BIT_WIDTH))
+ .withValue(copyFrom(DEFAULT_ORIGINAL_VALUE).fit(DEFAULT_BIT_WIDTH))
.build())
.build();
@@ -151,4 +150,4 @@
.addEqualityGroup(packetIn3)
.testEquals();
}
-}
\ No newline at end of file
+}
diff --git a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
index eebfb6b..709873e 100644
--- a/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
+++ b/protocols/p4runtime/ctl/src/test/java/org/onosproject/p4runtime/ctl/TableEntryEncoderTest.java
@@ -47,7 +47,6 @@
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
-import static org.onlab.util.ImmutableByteSequence.fit;
import static org.onlab.util.ImmutableByteSequence.ofOnes;
import static org.onosproject.net.pi.model.PiPipeconf.ExtensionType.P4_INFO_TEXT;
import static org.onosproject.p4runtime.ctl.TableEntryEncoder.decode;
@@ -84,7 +83,7 @@
.build();
private final P4InfoBrowser browser = PipeconfHelper.getP4InfoBrowser(defaultPipeconf);
- private final ImmutableByteSequence ethAddr = fit(copyFrom(rand.nextInt()), 48);
+ private final ImmutableByteSequence ethAddr = copyFrom(rand.nextInt()).fit(48);
private final ImmutableByteSequence portValue = copyFrom((short) rand.nextInt());
private final PiMatchFieldId ethDstAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + DST_ADDR);
private final PiMatchFieldId ethSrcAddrFieldId = PiMatchFieldId.of(HDR + DOT + ETHERNET + DOT + SRC_ADDR);
diff --git a/utils/misc/src/main/java/org/onlab/util/ImmutableByteSequence.java b/utils/misc/src/main/java/org/onlab/util/ImmutableByteSequence.java
index 2f98cfb..fea71a7 100644
--- a/utils/misc/src/main/java/org/onlab/util/ImmutableByteSequence.java
+++ b/utils/misc/src/main/java/org/onlab/util/ImmutableByteSequence.java
@@ -28,8 +28,8 @@
import static org.apache.commons.lang3.ArrayUtils.reverse;
/**
- * Immutable sequence of bytes, assumed to represent a value in
- * {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN} order.
+ * Immutable sequence of bytes, assumed to represent a value in {@link
+ * ByteOrder#BIG_ENDIAN BIG_ENDIAN} order.
* <p>
* Sequences can be created copying from an already existing representation of a
* sequence of bytes, such as {@link ByteBuffer} or {@code byte[]}; or by
@@ -40,6 +40,12 @@
*/
public final class ImmutableByteSequence {
+ private enum BitwiseOp {
+ AND,
+ OR,
+ XOR
+ }
+
/*
Actual bytes are backed by a byte buffer.
The order of a newly-created byte buffer is always BIG_ENDIAN.
@@ -47,8 +53,8 @@
private ByteBuffer value;
/**
- * Private constructor.
- * Creates a new byte sequence object backed by the passed ByteBuffer.
+ * Private constructor. Creates a new byte sequence object backed by the
+ * passed ByteBuffer.
*
* @param value a byte buffer
*/
@@ -210,7 +216,8 @@
}
/**
- * Creates a new byte sequence that is prefixed with specified number of zeros.
+ * Creates a new byte sequence that is prefixed with specified number of
+ * zeros.
*
* @param size number of total bytes
* @param prefixBits number of bits in prefix
@@ -221,7 +228,8 @@
}
/**
- * Creates a new byte sequence that is prefixed with specified number of ones.
+ * Creates a new byte sequence that is prefixed with specified number of
+ * ones.
*
* @param size number of total bytes
* @param prefixBits number of bits in prefix
@@ -266,6 +274,73 @@
return bytes;
}
+ private ImmutableByteSequence doBitwiseOp(ImmutableByteSequence other, BitwiseOp op) {
+ checkArgument(other != null && this.size() == other.size(),
+ "Other sequence must be non null and with same size as this");
+ byte[] newBytes = new byte[this.size()];
+ byte[] thisBytes = this.asArray();
+ byte[] otherBytes = other.asArray();
+ for (int i = 0; i < this.size(); i++) {
+ switch (op) {
+ case AND:
+ newBytes[i] = (byte) (thisBytes[i] & otherBytes[i]);
+ break;
+ case OR:
+ newBytes[i] = (byte) (thisBytes[i] | otherBytes[i]);
+ break;
+ case XOR:
+ newBytes[i] = (byte) (thisBytes[i] ^ otherBytes[i]);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown bitwise operator " + op.name());
+ }
+ }
+ return ImmutableByteSequence.copyFrom(newBytes);
+ }
+
+ /**
+ * Returns a new byte sequence corresponding to the result of a bitwise AND
+ * operation between this sequence and the given other, i.e. {@code this &
+ * other}.
+ *
+ * @param other other byte sequence
+ * @return new byte sequence
+ * @throws IllegalArgumentException if other sequence is null or its size is
+ * different than this sequence size
+ */
+ public ImmutableByteSequence bitwiseAnd(ImmutableByteSequence other) {
+ return doBitwiseOp(other, BitwiseOp.AND);
+ }
+
+ /**
+ * Returns a new byte sequence corresponding to the result of a bitwise OR
+ * operation between this sequence and the given other, i.e. {@code this |
+ * other}.
+ *
+ * @param other other byte sequence
+ * @return new byte sequence
+ * @throws IllegalArgumentException if other sequence is null or its size is
+ * different than this sequence size
+ */
+ public ImmutableByteSequence bitwiseOr(ImmutableByteSequence other) {
+ return doBitwiseOp(other, BitwiseOp.OR);
+ }
+
+ /**
+ * Returns a new byte sequence corresponding to the result of a bitwise XOR
+ * operation between this sequence and the given other, i.e. {@code this ^
+ * other}.
+ *
+ * @param other other byte sequence
+ * @return new byte sequence
+ * @throws IllegalArgumentException if other sequence is null or its size is
+ * different than this sequence size
+ */
+ public ImmutableByteSequence bitwiseXor(ImmutableByteSequence other) {
+ return doBitwiseOp(other, BitwiseOp.XOR);
+ }
+
@Override
public int hashCode() {
return value.hashCode();
@@ -284,19 +359,18 @@
}
/**
- * Returns the index of the most significant bit (MSB), assuming a bit numbering scheme of type "LSB 0", i.e. the
- * bit numbering starts at zero for the least significant bit (LSB). The MSB index of a byte sequence of zeros will
- * be -1.
+ * Returns the index of the most significant bit (MSB), assuming a bit
+ * numbering scheme of type "LSB 0", i.e. the bit numbering starts at zero
+ * for the least significant bit (LSB). The MSB index of a byte sequence of
+ * zeros will be -1.
* <p>
- * As an example, the following conditions always hold true:
- * {@code
+ * As an example, the following conditions always hold true: {@code
* ImmutableByteSequence.copyFrom(0).msbIndex() == -1
* ImmutableByteSequence.copyFrom(1).msbIndex() == 0
* ImmutableByteSequence.copyFrom(2).msbIndex() == 1
* ImmutableByteSequence.copyFrom(3).msbIndex() == 1
* ImmutableByteSequence.copyFrom(4).msbIndex() == 2
- * ImmutableByteSequence.copyFrom(512).msbIndex() == 9
- * }
+ * ImmutableByteSequence.copyFrom(512).msbIndex() == 9 }
*
* @return index of the MSB, -1 if the sequence has all bytes set to 0
*/
@@ -325,17 +399,45 @@
}
/**
- * Trims or expands the given byte sequence so to fit a given bit-width. When trimming, the operations is deemed to
- * be safe only if the trimmed bits are zero, i.e. it is safe to trim only when {@code bitWidth > msbIndex()},
- * otherwise an exception will be thrown. When expanding, the sequence will be padded with zeros. The returned byte
- * sequence will have minimum size to contain the given bit-width.
+ * Trims or expands a copy of this byte sequence so to fit the given
+ * bit-width. When trimming, the operations is deemed to be safe only if the
+ * trimmed bits are zero, i.e. it is safe to trim only when {@code bitWidth
+ * > msbIndex()}, otherwise an exception will be thrown. When expanding, the
+ * sequence will be padded with zeros. The returned byte sequence will have
+ * minimum size to contain the given bit-width.
+ *
+ * @param bitWidth a non-zero positive integer
+ * @return a new byte sequence
+ * @throws ByteSequenceTrimException if the byte sequence cannot be fitted
+ */
+ public ImmutableByteSequence fit(int bitWidth) throws ByteSequenceTrimException {
+ return doFit(this, bitWidth);
+ }
+
+ /**
+ * Trims or expands the given byte sequence so to fit a given bit-width.
+ * When trimming, the operations is deemed to be safe only if the trimmed
+ * bits are zero, i.e. it is safe to trim only when {@code bitWidth >
+ * msbIndex()}, otherwise an exception will be thrown. When expanding, the
+ * sequence will be padded with zeros. The returned byte sequence will have
+ * minimum size to contain the given bit-width.
*
* @param original a byte sequence
* @param bitWidth a non-zero positive integer
* @return a new byte sequence
* @throws ByteSequenceTrimException if the byte sequence cannot be fitted
+ * @deprecated in ONOS 1.13, use {@link ImmutableByteSequence#fit(int)}
+ * instead.
*/
- public static ImmutableByteSequence fit(ImmutableByteSequence original, int bitWidth)
+ @Deprecated
+ public static ImmutableByteSequence fit(ImmutableByteSequence original,
+ int bitWidth)
+ throws ByteSequenceTrimException {
+ return doFit(original, bitWidth);
+ }
+
+ private static ImmutableByteSequence doFit(ImmutableByteSequence original,
+ int bitWidth)
throws ByteSequenceTrimException {
checkNotNull(original, "byte sequence cannot be null");
diff --git a/utils/misc/src/test/java/org/onlab/util/ImmutableByteSequenceTest.java b/utils/misc/src/test/java/org/onlab/util/ImmutableByteSequenceTest.java
index 76981e8..7e74328 100644
--- a/utils/misc/src/test/java/org/onlab/util/ImmutableByteSequenceTest.java
+++ b/utils/misc/src/test/java/org/onlab/util/ImmutableByteSequenceTest.java
@@ -17,7 +17,6 @@
package org.onlab.util;
import com.google.common.testing.EqualsTester;
-
import org.apache.commons.lang3.RandomUtils;
import org.junit.Assert;
import org.junit.Rule;
@@ -207,7 +206,7 @@
private void checkIllegalFit(ImmutableByteSequence bytes, int bitWidth) {
try {
- ImmutableByteSequence.fit(bytes, bitWidth);
+ bytes.fit(bitWidth);
Assert.fail(format("Except ByteSequenceTrimException due to value = %s and bitWidth %d",
bytes.toString(), bitWidth));
} catch (ImmutableByteSequence.ByteSequenceTrimException e) {
@@ -217,8 +216,8 @@
private void checkLegalFit(ImmutableByteSequence bytes, int bitWidth)
throws ImmutableByteSequence.ByteSequenceTrimException {
- ImmutableByteSequence fitBytes = ImmutableByteSequence.fit(bytes, bitWidth);
- ImmutableByteSequence sameBytes = ImmutableByteSequence.fit(fitBytes, bytes.size() * 8);
+ ImmutableByteSequence fitBytes = bytes.fit(bitWidth);
+ ImmutableByteSequence sameBytes = fitBytes.fit(bytes.size() * 8);
assertThat(format("Fitted value %s (re-extended to %s) not equal to original value %s",
fitBytes, sameBytes, bytes),
sameBytes,
@@ -254,4 +253,25 @@
checkLegalFit(bytes, msbIndex + 1);
}
}
-}
\ No newline at end of file
+
+ @Test
+ public void testBitwiseOperations() {
+ Random random = new Random();
+ long long1 = random.nextLong();
+ long long2 = random.nextLong();
+
+ ImmutableByteSequence bs1 = ImmutableByteSequence.copyFrom(long1);
+ ImmutableByteSequence bs2 = ImmutableByteSequence.copyFrom(long2);
+
+ ImmutableByteSequence andBs = bs1.bitwiseAnd(bs2);
+ ImmutableByteSequence orBs = bs1.bitwiseOr(bs2);
+ ImmutableByteSequence xorBs = bs1.bitwiseXor(bs2);
+
+ assertThat("Invalid bitwise AND result",
+ andBs.asReadOnlyBuffer().getLong(), is(long1 & long2));
+ assertThat("Invalid bitwise OR result",
+ orBs.asReadOnlyBuffer().getLong(), is(long1 | long2));
+ assertThat("Invalid bitwise XOR result",
+ xorBs.asReadOnlyBuffer().getLong(), is(long1 ^ long2));
+ }
+}