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 c90ea35367..47df7f188e 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 java.util.Optional; 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 @@ public final class PipelineInterpreterImpl extends AbstractHandlerBehaviour impl 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 319afec01f..6c320ad116 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.CompletableFuture; 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 @@ public class P4RuntimeTest { .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 @@ public class P4RuntimeTest { 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 36e90684c7..9b2b4a04f5 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 org.onosproject.net.pi.model.PiMatchType; 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 @@ abstract class AbstractCriterionTranslator implements CriterionTranslator { 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 @@ abstract class AbstractCriterionTranslator implements CriterionTranslator { 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 @@ abstract class AbstractCriterionTranslator implements CriterionTranslator { 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 b4ce83059e..85c763caa2 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 java.util.StringJoiner; 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 @@ final class PiFlowRuleTranslatorImpl { "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 @@ final class PiFlowRuleTranslatorImpl { 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 @@ final class PiFlowRuleTranslatorImpl { 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 1d0caee105..9af674533d 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.equalTo; 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 @@ public class PiTranslatorServiceTest { 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 8e7b399522..5ff38baaf7 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 java.util.Optional; 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 @@ public class BasicInterpreterImpl extends AbstractHandlerBehaviour 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 @@ public class BasicInterpreterImpl extends AbstractHandlerBehaviour 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 29e3a485c6..e79cd44405 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 java.util.Set; 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 @@ public class FabricInterpreter extends AbstractHandlerBehaviour 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 63463022e8..00c4047cc7 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 @@ final class FabricTreatmentInterpreter { 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 8d97f209b6..c60a5e8670 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 @@ public class FabricInterpreterTest { 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 38fcf6d459..5993142051 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.Before; 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 @@ public class DefaultPacketInTest { .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 @@ public class DefaultPacketInTest { .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 @@ public class DefaultPacketInTest { .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 eebfb6b775..709873e5c2 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.MatcherAssert.assertThat; 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 @@ public class TableEntryEncoderTest { .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 2f98cfbd20..fea71a7219 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 java.lang.String.format; 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. *

* 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 @@ import static org.apache.commons.lang3.ArrayUtils.reverse; */ 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 @@ public final class ImmutableByteSequence { 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 @@ public final class ImmutableByteSequence { } /** - * 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 @@ public final class ImmutableByteSequence { } /** - * 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 @@ public final class ImmutableByteSequence { 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 @@ public final class ImmutableByteSequence { } /** - * 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. *

- * 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 @@ public final class ImmutableByteSequence { } /** - * 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 76981e8c41..7e74328a19 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 @@ public class ImmutableByteSequenceTest { 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 @@ public class ImmutableByteSequenceTest { 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 @@ public class ImmutableByteSequenceTest { 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)); + } +}