mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-05 20:26:16 +02:00
Support for bitwise AND/OR/XOR in ImmutableByteSequence
Also, minor refactoring of the fit() method to improve code readability Change-Id: I826650c3fc45573c723d9d2dd8692da174d9ae08
This commit is contained in:
parent
3dca0f8fb1
commit
8a571af574
@ -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()));
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
* <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 @@ 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.
|
||||
* <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 @@ 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");
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user