dcsctp: UnwrappedSequenceNumber use StrongAlias

As this library will only use StrongAlias types for all its
sequence numbers, the UnwrappedSequenceNumber class should use those
types and not the primitive underlying types (e.g. uint32_t).

This makes e.g. Unwrap() return a strong type, which is preferred.

Bug: webrtc:12614
Change-Id: Icd0900c643a1988d1a3bbf49d87b4d4d1bbfbf1f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213663
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33651}
This commit is contained in:
Victor Boivie 2021-04-02 00:18:48 +02:00 committed by Commit Bot
parent 471fc8c329
commit 83c726f3e5
3 changed files with 52 additions and 41 deletions

View File

@ -14,6 +14,8 @@
#include <limits>
#include <utility>
#include "net/dcsctp/common/internal_types.h"
namespace dcsctp {
// UnwrappedSequenceNumber handles wrapping sequence numbers and unwraps them to
@ -23,14 +25,18 @@ namespace dcsctp {
// Sequence numbers are expected to be monotonically increasing, but they do not
// need to be unwrapped in order, as long as the difference to the previous one
// is not larger than half the range of the wrapped sequence number.
//
// The WrappedType must be a StrongAlias type.
template <typename WrappedType>
class UnwrappedSequenceNumber {
public:
static_assert(!std::numeric_limits<WrappedType>::is_signed,
"The wrapped type must be unsigned");
static_assert(std::numeric_limits<WrappedType>::max() <
std::numeric_limits<int64_t>::max(),
"The wrapped type must be less than the int64_t value space");
static_assert(
!std::numeric_limits<typename WrappedType::UnderlyingType>::is_signed,
"The wrapped type must be unsigned");
static_assert(
std::numeric_limits<typename WrappedType::UnderlyingType>::max() <
std::numeric_limits<int64_t>::max(),
"The wrapped type must be less than the int64_t value space");
// The unwrapper is a sort of factory and converts wrapped sequence numbers to
// unwrapped ones.
@ -70,8 +76,9 @@ class UnwrappedSequenceNumber {
private:
static int64_t Delta(WrappedType value, WrappedType prev_value) {
static constexpr WrappedType kBreakpoint = kValueLimit / 2;
WrappedType diff = value - prev_value;
static constexpr typename WrappedType::UnderlyingType kBreakpoint =
kValueLimit / 2;
typename WrappedType::UnderlyingType diff = *value - *prev_value;
diff %= kValueLimit;
if (diff < kBreakpoint) {
return static_cast<int64_t>(diff);
@ -124,26 +131,28 @@ class UnwrappedSequenceNumber {
}
// Compares the difference between two sequence numbers.
WrappedType Difference(UnwrappedSequenceNumber<WrappedType> other) const {
typename WrappedType::UnderlyingType Difference(
UnwrappedSequenceNumber<WrappedType> other) const {
return value_ - other.value_;
}
private:
explicit UnwrappedSequenceNumber(int64_t value) : value_(value) {}
static constexpr int64_t kValueLimit =
static_cast<int64_t>(1) << std::numeric_limits<WrappedType>::digits;
static_cast<int64_t>(1)
<< std::numeric_limits<typename WrappedType::UnderlyingType>::digits;
int64_t value_;
};
// Unwrapped Transmission Sequence Numbers (TSN)
using UnwrappedTSN = UnwrappedSequenceNumber<uint32_t>;
using UnwrappedTSN = UnwrappedSequenceNumber<TSN>;
// Unwrapped Stream Sequence Numbers (SSN)
using UnwrappedSSN = UnwrappedSequenceNumber<uint16_t>;
using UnwrappedSSN = UnwrappedSequenceNumber<SSN>;
// Unwrapped Message Identifier (MID)
using UnwrappedMID = UnwrappedSequenceNumber<uint32_t>;
using UnwrappedMID = UnwrappedSequenceNumber<MID>;
} // namespace dcsctp

View File

@ -14,15 +14,16 @@
namespace dcsctp {
namespace {
using TestSequence = UnwrappedSequenceNumber<uint16_t>;
using Wrapped = StrongAlias<class WrappedTag, uint16_t>;
using TestSequence = UnwrappedSequenceNumber<Wrapped>;
TEST(SequenceNumbersTest, SimpleUnwrapping) {
TestSequence::Unwrapper unwrapper;
TestSequence s0 = unwrapper.Unwrap(0);
TestSequence s1 = unwrapper.Unwrap(1);
TestSequence s2 = unwrapper.Unwrap(2);
TestSequence s3 = unwrapper.Unwrap(3);
TestSequence s0 = unwrapper.Unwrap(Wrapped(0));
TestSequence s1 = unwrapper.Unwrap(Wrapped(1));
TestSequence s2 = unwrapper.Unwrap(Wrapped(2));
TestSequence s3 = unwrapper.Unwrap(Wrapped(3));
EXPECT_LT(s0, s1);
EXPECT_LT(s0, s2);
@ -55,10 +56,10 @@ TEST(SequenceNumbersTest, SimpleUnwrapping) {
TEST(SequenceNumbersTest, MidValueUnwrapping) {
TestSequence::Unwrapper unwrapper;
TestSequence s0 = unwrapper.Unwrap(0x7FFE);
TestSequence s1 = unwrapper.Unwrap(0x7FFF);
TestSequence s2 = unwrapper.Unwrap(0x8000);
TestSequence s3 = unwrapper.Unwrap(0x8001);
TestSequence s0 = unwrapper.Unwrap(Wrapped(0x7FFE));
TestSequence s1 = unwrapper.Unwrap(Wrapped(0x7FFF));
TestSequence s2 = unwrapper.Unwrap(Wrapped(0x8000));
TestSequence s3 = unwrapper.Unwrap(Wrapped(0x8001));
EXPECT_LT(s0, s1);
EXPECT_LT(s0, s2);
@ -91,10 +92,10 @@ TEST(SequenceNumbersTest, MidValueUnwrapping) {
TEST(SequenceNumbersTest, WrappedUnwrapping) {
TestSequence::Unwrapper unwrapper;
TestSequence s0 = unwrapper.Unwrap(0xFFFE);
TestSequence s1 = unwrapper.Unwrap(0xFFFF);
TestSequence s2 = unwrapper.Unwrap(0x0000);
TestSequence s3 = unwrapper.Unwrap(0x0001);
TestSequence s0 = unwrapper.Unwrap(Wrapped(0xFFFE));
TestSequence s1 = unwrapper.Unwrap(Wrapped(0xFFFF));
TestSequence s2 = unwrapper.Unwrap(Wrapped(0x0000));
TestSequence s3 = unwrapper.Unwrap(Wrapped(0x0001));
EXPECT_LT(s0, s1);
EXPECT_LT(s0, s2);
@ -127,12 +128,12 @@ TEST(SequenceNumbersTest, WrappedUnwrapping) {
TEST(SequenceNumbersTest, WrapAroundAFewTimes) {
TestSequence::Unwrapper unwrapper;
TestSequence s0 = unwrapper.Unwrap(0);
TestSequence s0 = unwrapper.Unwrap(Wrapped(0));
TestSequence prev = s0;
for (uint32_t i = 1; i < 65536 * 3; i++) {
uint16_t wrapped = static_cast<uint16_t>(i);
TestSequence si = unwrapper.Unwrap(wrapped);
TestSequence si = unwrapper.Unwrap(Wrapped(wrapped));
EXPECT_LT(s0, si);
EXPECT_LT(prev, si);
@ -143,11 +144,11 @@ TEST(SequenceNumbersTest, WrapAroundAFewTimes) {
TEST(SequenceNumbersTest, IncrementIsSameAsWrapped) {
TestSequence::Unwrapper unwrapper;
TestSequence s0 = unwrapper.Unwrap(0);
TestSequence s0 = unwrapper.Unwrap(Wrapped(0));
for (uint32_t i = 1; i < 65536 * 2; i++) {
uint16_t wrapped = static_cast<uint16_t>(i);
TestSequence si = unwrapper.Unwrap(wrapped);
TestSequence si = unwrapper.Unwrap(Wrapped(wrapped));
s0.Increment();
EXPECT_EQ(s0, si);
@ -159,12 +160,12 @@ TEST(SequenceNumbersTest, UnwrappingLargerNumberIsAlwaysLarger) {
for (uint32_t i = 1; i < 65536 * 2; i++) {
uint16_t wrapped = static_cast<uint16_t>(i);
TestSequence si = unwrapper.Unwrap(wrapped);
TestSequence si = unwrapper.Unwrap(Wrapped(wrapped));
EXPECT_GT(unwrapper.Unwrap(wrapped + 1), si);
EXPECT_GT(unwrapper.Unwrap(wrapped + 5), si);
EXPECT_GT(unwrapper.Unwrap(wrapped + 10), si);
EXPECT_GT(unwrapper.Unwrap(wrapped + 100), si);
EXPECT_GT(unwrapper.Unwrap(Wrapped(wrapped + 1)), si);
EXPECT_GT(unwrapper.Unwrap(Wrapped(wrapped + 5)), si);
EXPECT_GT(unwrapper.Unwrap(Wrapped(wrapped + 10)), si);
EXPECT_GT(unwrapper.Unwrap(Wrapped(wrapped + 100)), si);
}
}
@ -173,12 +174,12 @@ TEST(SequenceNumbersTest, UnwrappingSmallerNumberIsAlwaysSmaller) {
for (uint32_t i = 1; i < 65536 * 2; i++) {
uint16_t wrapped = static_cast<uint16_t>(i);
TestSequence si = unwrapper.Unwrap(wrapped);
TestSequence si = unwrapper.Unwrap(Wrapped(wrapped));
EXPECT_LT(unwrapper.Unwrap(wrapped - 1), si);
EXPECT_LT(unwrapper.Unwrap(wrapped - 5), si);
EXPECT_LT(unwrapper.Unwrap(wrapped - 10), si);
EXPECT_LT(unwrapper.Unwrap(wrapped - 100), si);
EXPECT_LT(unwrapper.Unwrap(Wrapped(wrapped - 1)), si);
EXPECT_LT(unwrapper.Unwrap(Wrapped(wrapped - 5)), si);
EXPECT_LT(unwrapper.Unwrap(Wrapped(wrapped - 10)), si);
EXPECT_LT(unwrapper.Unwrap(Wrapped(wrapped - 100)), si);
}
}

View File

@ -20,11 +20,12 @@ namespace dcsctp {
// https://source.chromium.org/chromium/chromium/src/+/master:base/types/strong_alias.h
// as the API (and internals) are using type-safe integral identifiers, but this
// library can't depend on that file. The ostream operator has been removed
// per WebRTC library conventions.
// per WebRTC library conventions, and the underlying type is exposed.
template <typename TagType, typename UnderlyingType>
template <typename TagType, typename TheUnderlyingType>
class StrongAlias {
public:
using UnderlyingType = TheUnderlyingType;
constexpr StrongAlias() = default;
constexpr explicit StrongAlias(const UnderlyingType& v) : value_(v) {}
constexpr explicit StrongAlias(UnderlyingType&& v) noexcept