dcsctp: Added common utilities
These are quite generic utilities that are used by multiple modules within dcSCTP. Some would be good to have in rtc_base and are simple replicas of utilities available in abseil. Bug: webrtc:12614 Change-Id: I9914286ced7317a34628a71697da9149d6d19d38 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213190 Reviewed-by: Tommi <tommi@webrtc.org> Commit-Queue: Victor Boivie <boivie@webrtc.org> Cr-Commit-Position: refs/heads/master@{#33609}
This commit is contained in:
parent
5457ec05b4
commit
a4d5e24c11
@ -13,6 +13,7 @@ if (rtc_include_tests) {
|
||||
testonly = true
|
||||
deps = [
|
||||
"../../test:test_main",
|
||||
"common:dcsctp_common_unittests",
|
||||
"packet:dcsctp_packet_unittests",
|
||||
]
|
||||
}
|
||||
|
||||
55
net/dcsctp/common/BUILD.gn
Normal file
55
net/dcsctp/common/BUILD.gn
Normal file
@ -0,0 +1,55 @@
|
||||
# Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
import("//build/config/linux/pkg_config.gni")
|
||||
import("../../../webrtc.gni")
|
||||
|
||||
rtc_source_set("math") {
|
||||
deps = []
|
||||
sources = [ "math.h" ]
|
||||
}
|
||||
|
||||
rtc_source_set("pair_hash") {
|
||||
deps = []
|
||||
sources = [ "pair_hash.h" ]
|
||||
}
|
||||
|
||||
rtc_source_set("sequence_numbers") {
|
||||
deps = []
|
||||
sources = [ "sequence_numbers.h" ]
|
||||
}
|
||||
|
||||
rtc_source_set("str_join") {
|
||||
deps = []
|
||||
sources = [ "str_join.h" ]
|
||||
}
|
||||
|
||||
if (rtc_include_tests) {
|
||||
rtc_library("dcsctp_common_unittests") {
|
||||
testonly = true
|
||||
|
||||
defines = []
|
||||
deps = [
|
||||
":math",
|
||||
":pair_hash",
|
||||
":sequence_numbers",
|
||||
":str_join",
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:gunit_helpers",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../test:test_support",
|
||||
]
|
||||
sources = [
|
||||
"math_test.cc",
|
||||
"pair_hash_test.cc",
|
||||
"sequence_numbers_test.cc",
|
||||
"str_join_test.cc",
|
||||
]
|
||||
}
|
||||
}
|
||||
24
net/dcsctp/common/math.h
Normal file
24
net/dcsctp/common/math.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef NET_DCSCTP_COMMON_MATH_H_
|
||||
#define NET_DCSCTP_COMMON_MATH_H_
|
||||
|
||||
namespace dcsctp {
|
||||
|
||||
// Rounds up `val` to the nearest value that is divisible by four. Frequently
|
||||
// used to e.g. pad chunks or parameters to an even 32-bit offset.
|
||||
template <typename IntType>
|
||||
IntType RoundUpTo4(IntType val) {
|
||||
return (val + 3) & -4;
|
||||
}
|
||||
|
||||
} // namespace dcsctp
|
||||
|
||||
#endif // NET_DCSCTP_COMMON_MATH_H_
|
||||
32
net/dcsctp/common/math_test.cc
Normal file
32
net/dcsctp/common/math_test.cc
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include "net/dcsctp/common/math.h"
|
||||
|
||||
#include "test/gmock.h"
|
||||
|
||||
namespace dcsctp {
|
||||
namespace {
|
||||
|
||||
TEST(MathUtilTest, CanRoundUpTo4) {
|
||||
EXPECT_EQ(RoundUpTo4(0), 0);
|
||||
EXPECT_EQ(RoundUpTo4(1), 4);
|
||||
EXPECT_EQ(RoundUpTo4(2), 4);
|
||||
EXPECT_EQ(RoundUpTo4(3), 4);
|
||||
EXPECT_EQ(RoundUpTo4(4), 4);
|
||||
EXPECT_EQ(RoundUpTo4(5), 8);
|
||||
EXPECT_EQ(RoundUpTo4(6), 8);
|
||||
EXPECT_EQ(RoundUpTo4(7), 8);
|
||||
EXPECT_EQ(RoundUpTo4(8), 8);
|
||||
EXPECT_EQ(RoundUpTo4(10000000000), 10000000000);
|
||||
EXPECT_EQ(RoundUpTo4(10000000001), 10000000004);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace dcsctp
|
||||
31
net/dcsctp/common/pair_hash.h
Normal file
31
net/dcsctp/common/pair_hash.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef NET_DCSCTP_COMMON_PAIR_HASH_H_
|
||||
#define NET_DCSCTP_COMMON_PAIR_HASH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace dcsctp {
|
||||
|
||||
// A custom hash function for std::pair, to be able to be used as key in a
|
||||
// std::unordered_map. If absl::flat_hash_map would ever be used, this is
|
||||
// unnecessary as it already has a hash function for std::pair.
|
||||
struct PairHash {
|
||||
template <class T1, class T2>
|
||||
size_t operator()(const std::pair<T1, T2>& p) const {
|
||||
return (3 * std::hash<T1>{}(p.first)) ^ std::hash<T2>{}(p.second);
|
||||
}
|
||||
};
|
||||
} // namespace dcsctp
|
||||
|
||||
#endif // NET_DCSCTP_COMMON_PAIR_HASH_H_
|
||||
48
net/dcsctp/common/pair_hash_test.cc
Normal file
48
net/dcsctp/common/pair_hash_test.cc
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include "net/dcsctp/common/pair_hash.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "test/gmock.h"
|
||||
|
||||
namespace dcsctp {
|
||||
namespace {
|
||||
|
||||
TEST(PairHashTest, CanInsertIntoSet) {
|
||||
using MyPair = std::pair<int, int>;
|
||||
|
||||
std::unordered_set<MyPair, PairHash> pairs;
|
||||
|
||||
pairs.insert({1, 2});
|
||||
pairs.insert({3, 4});
|
||||
|
||||
EXPECT_NE(pairs.find({1, 2}), pairs.end());
|
||||
EXPECT_NE(pairs.find({3, 4}), pairs.end());
|
||||
EXPECT_EQ(pairs.find({1, 3}), pairs.end());
|
||||
EXPECT_EQ(pairs.find({3, 3}), pairs.end());
|
||||
}
|
||||
|
||||
TEST(PairHashTest, CanInsertIntoMap) {
|
||||
using MyPair = std::pair<int, int>;
|
||||
|
||||
std::unordered_map<MyPair, int, PairHash> pairs;
|
||||
|
||||
pairs[{1, 2}] = 99;
|
||||
pairs[{3, 4}] = 100;
|
||||
|
||||
EXPECT_EQ((pairs[{1, 2}]), 99);
|
||||
EXPECT_EQ((pairs[{3, 4}]), 100);
|
||||
EXPECT_EQ(pairs.find({1, 3}), pairs.end());
|
||||
EXPECT_EQ(pairs.find({3, 3}), pairs.end());
|
||||
}
|
||||
} // namespace
|
||||
} // namespace dcsctp
|
||||
150
net/dcsctp/common/sequence_numbers.h
Normal file
150
net/dcsctp/common/sequence_numbers.h
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_
|
||||
#define NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
namespace dcsctp {
|
||||
|
||||
// UnwrappedSequenceNumber handles wrapping sequence numbers and unwraps them to
|
||||
// an int64_t value space, to allow wrapped sequence numbers to be easily
|
||||
// compared for ordering.
|
||||
//
|
||||
// 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.
|
||||
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");
|
||||
|
||||
// The unwrapper is a sort of factory and converts wrapped sequence numbers to
|
||||
// unwrapped ones.
|
||||
class Unwrapper {
|
||||
public:
|
||||
Unwrapper() : largest_(kValueLimit) {}
|
||||
Unwrapper(const Unwrapper&) = default;
|
||||
Unwrapper& operator=(const Unwrapper&) = default;
|
||||
|
||||
// Given a wrapped `value`, and with knowledge of its current last seen
|
||||
// largest number, will return a value that can be compared using normal
|
||||
// operators, such as less-than, greater-than etc.
|
||||
//
|
||||
// This will also update the Unwrapper's state, to track the last seen
|
||||
// largest value.
|
||||
UnwrappedSequenceNumber<WrappedType> Unwrap(WrappedType value) {
|
||||
WrappedType wrapped_largest =
|
||||
static_cast<WrappedType>(largest_ % kValueLimit);
|
||||
int64_t result = largest_ + Delta(value, wrapped_largest);
|
||||
if (largest_ < result) {
|
||||
largest_ = result;
|
||||
}
|
||||
return UnwrappedSequenceNumber<WrappedType>(result);
|
||||
}
|
||||
|
||||
// Similar to `Unwrap`, but will not update the Unwrappers's internal state.
|
||||
UnwrappedSequenceNumber<WrappedType> PeekUnwrap(WrappedType value) const {
|
||||
WrappedType uint32_largest =
|
||||
static_cast<WrappedType>(largest_ % kValueLimit);
|
||||
int64_t result = largest_ + Delta(value, uint32_largest);
|
||||
return UnwrappedSequenceNumber<WrappedType>(result);
|
||||
}
|
||||
|
||||
// Resets the Unwrapper to its pristine state. Used when a sequence number
|
||||
// is to be reset to zero.
|
||||
void Reset() { largest_ = kValueLimit; }
|
||||
|
||||
private:
|
||||
static int64_t Delta(WrappedType value, WrappedType prev_value) {
|
||||
static constexpr WrappedType kBreakpoint = kValueLimit / 2;
|
||||
WrappedType diff = value - prev_value;
|
||||
diff %= kValueLimit;
|
||||
if (diff < kBreakpoint) {
|
||||
return static_cast<int64_t>(diff);
|
||||
}
|
||||
return static_cast<int64_t>(diff) - kValueLimit;
|
||||
}
|
||||
|
||||
int64_t largest_;
|
||||
};
|
||||
|
||||
// Returns the wrapped value this type represents.
|
||||
WrappedType Wrap() const {
|
||||
return static_cast<WrappedType>(value_ % kValueLimit);
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H state,
|
||||
const UnwrappedSequenceNumber<WrappedType>& hash) {
|
||||
return H::combine(std::move(state), hash.value_);
|
||||
}
|
||||
|
||||
bool operator==(const UnwrappedSequenceNumber<WrappedType>& other) const {
|
||||
return value_ == other.value_;
|
||||
}
|
||||
bool operator!=(const UnwrappedSequenceNumber<WrappedType>& other) const {
|
||||
return value_ != other.value_;
|
||||
}
|
||||
bool operator<(const UnwrappedSequenceNumber<WrappedType>& other) const {
|
||||
return value_ < other.value_;
|
||||
}
|
||||
bool operator>(const UnwrappedSequenceNumber<WrappedType>& other) const {
|
||||
return value_ > other.value_;
|
||||
}
|
||||
bool operator>=(const UnwrappedSequenceNumber<WrappedType>& other) const {
|
||||
return value_ >= other.value_;
|
||||
}
|
||||
bool operator<=(const UnwrappedSequenceNumber<WrappedType>& other) const {
|
||||
return value_ <= other.value_;
|
||||
}
|
||||
|
||||
// Increments the value.
|
||||
void Increment() { ++value_; }
|
||||
UnwrappedSequenceNumber<WrappedType> next_value() const {
|
||||
return UnwrappedSequenceNumber<WrappedType>(value_ + 1);
|
||||
}
|
||||
|
||||
// Adds a delta to the current value.
|
||||
UnwrappedSequenceNumber<WrappedType> AddTo(int delta) const {
|
||||
return UnwrappedSequenceNumber<WrappedType>(value_ + delta);
|
||||
}
|
||||
|
||||
// Compares the difference between two sequence numbers.
|
||||
WrappedType 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;
|
||||
|
||||
int64_t value_;
|
||||
};
|
||||
|
||||
// Transmission Sequence Numbers (TSN)
|
||||
using TSN = UnwrappedSequenceNumber<uint32_t>;
|
||||
|
||||
// Stream Sequence Numbers (SSN)
|
||||
using SSN = UnwrappedSequenceNumber<uint16_t>;
|
||||
|
||||
// Message Identifier (MID)
|
||||
using MID = UnwrappedSequenceNumber<uint32_t>;
|
||||
|
||||
} // namespace dcsctp
|
||||
|
||||
#endif // NET_DCSCTP_COMMON_SEQUENCE_NUMBERS_H_
|
||||
186
net/dcsctp/common/sequence_numbers_test.cc
Normal file
186
net/dcsctp/common/sequence_numbers_test.cc
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include "net/dcsctp/common/sequence_numbers.h"
|
||||
|
||||
#include "test/gmock.h"
|
||||
|
||||
namespace dcsctp {
|
||||
namespace {
|
||||
|
||||
using TestSequence = UnwrappedSequenceNumber<uint16_t>;
|
||||
|
||||
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);
|
||||
|
||||
EXPECT_LT(s0, s1);
|
||||
EXPECT_LT(s0, s2);
|
||||
EXPECT_LT(s0, s3);
|
||||
EXPECT_LT(s1, s2);
|
||||
EXPECT_LT(s1, s3);
|
||||
EXPECT_LT(s2, s3);
|
||||
|
||||
EXPECT_EQ(s1.Difference(s0), 1);
|
||||
EXPECT_EQ(s2.Difference(s0), 2);
|
||||
EXPECT_EQ(s3.Difference(s0), 3);
|
||||
|
||||
EXPECT_GT(s1, s0);
|
||||
EXPECT_GT(s2, s0);
|
||||
EXPECT_GT(s3, s0);
|
||||
EXPECT_GT(s2, s1);
|
||||
EXPECT_GT(s3, s1);
|
||||
EXPECT_GT(s3, s2);
|
||||
|
||||
s0.Increment();
|
||||
EXPECT_EQ(s0, s1);
|
||||
s1.Increment();
|
||||
EXPECT_EQ(s1, s2);
|
||||
s2.Increment();
|
||||
EXPECT_EQ(s2, s3);
|
||||
|
||||
EXPECT_EQ(s0.AddTo(2), s3);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
EXPECT_LT(s0, s1);
|
||||
EXPECT_LT(s0, s2);
|
||||
EXPECT_LT(s0, s3);
|
||||
EXPECT_LT(s1, s2);
|
||||
EXPECT_LT(s1, s3);
|
||||
EXPECT_LT(s2, s3);
|
||||
|
||||
EXPECT_EQ(s1.Difference(s0), 1);
|
||||
EXPECT_EQ(s2.Difference(s0), 2);
|
||||
EXPECT_EQ(s3.Difference(s0), 3);
|
||||
|
||||
EXPECT_GT(s1, s0);
|
||||
EXPECT_GT(s2, s0);
|
||||
EXPECT_GT(s3, s0);
|
||||
EXPECT_GT(s2, s1);
|
||||
EXPECT_GT(s3, s1);
|
||||
EXPECT_GT(s3, s2);
|
||||
|
||||
s0.Increment();
|
||||
EXPECT_EQ(s0, s1);
|
||||
s1.Increment();
|
||||
EXPECT_EQ(s1, s2);
|
||||
s2.Increment();
|
||||
EXPECT_EQ(s2, s3);
|
||||
|
||||
EXPECT_EQ(s0.AddTo(2), s3);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
EXPECT_LT(s0, s1);
|
||||
EXPECT_LT(s0, s2);
|
||||
EXPECT_LT(s0, s3);
|
||||
EXPECT_LT(s1, s2);
|
||||
EXPECT_LT(s1, s3);
|
||||
EXPECT_LT(s2, s3);
|
||||
|
||||
EXPECT_EQ(s1.Difference(s0), 1);
|
||||
EXPECT_EQ(s2.Difference(s0), 2);
|
||||
EXPECT_EQ(s3.Difference(s0), 3);
|
||||
|
||||
EXPECT_GT(s1, s0);
|
||||
EXPECT_GT(s2, s0);
|
||||
EXPECT_GT(s3, s0);
|
||||
EXPECT_GT(s2, s1);
|
||||
EXPECT_GT(s3, s1);
|
||||
EXPECT_GT(s3, s2);
|
||||
|
||||
s0.Increment();
|
||||
EXPECT_EQ(s0, s1);
|
||||
s1.Increment();
|
||||
EXPECT_EQ(s1, s2);
|
||||
s2.Increment();
|
||||
EXPECT_EQ(s2, s3);
|
||||
|
||||
EXPECT_EQ(s0.AddTo(2), s3);
|
||||
}
|
||||
|
||||
TEST(SequenceNumbersTest, WrapAroundAFewTimes) {
|
||||
TestSequence::Unwrapper unwrapper;
|
||||
|
||||
TestSequence s0 = unwrapper.Unwrap(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);
|
||||
|
||||
EXPECT_LT(s0, si);
|
||||
EXPECT_LT(prev, si);
|
||||
prev = si;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SequenceNumbersTest, IncrementIsSameAsWrapped) {
|
||||
TestSequence::Unwrapper unwrapper;
|
||||
|
||||
TestSequence s0 = unwrapper.Unwrap(0);
|
||||
|
||||
for (uint32_t i = 1; i < 65536 * 2; i++) {
|
||||
uint16_t wrapped = static_cast<uint16_t>(i);
|
||||
TestSequence si = unwrapper.Unwrap(wrapped);
|
||||
|
||||
s0.Increment();
|
||||
EXPECT_EQ(s0, si);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SequenceNumbersTest, UnwrappingLargerNumberIsAlwaysLarger) {
|
||||
TestSequence::Unwrapper unwrapper;
|
||||
|
||||
for (uint32_t i = 1; i < 65536 * 2; i++) {
|
||||
uint16_t wrapped = static_cast<uint16_t>(i);
|
||||
TestSequence si = unwrapper.Unwrap(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);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SequenceNumbersTest, UnwrappingSmallerNumberIsAlwaysSmaller) {
|
||||
TestSequence::Unwrapper unwrapper;
|
||||
|
||||
for (uint32_t i = 1; i < 65536 * 2; i++) {
|
||||
uint16_t wrapped = static_cast<uint16_t>(i);
|
||||
TestSequence si = unwrapper.Unwrap(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);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace dcsctp
|
||||
56
net/dcsctp/common/str_join.h
Normal file
56
net/dcsctp/common/str_join.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#ifndef NET_DCSCTP_COMMON_STR_JOIN_H_
|
||||
#define NET_DCSCTP_COMMON_STR_JOIN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
|
||||
namespace dcsctp {
|
||||
|
||||
template <typename Range>
|
||||
std::string StrJoin(const Range& seq, absl::string_view delimiter) {
|
||||
rtc::StringBuilder sb;
|
||||
int idx = 0;
|
||||
|
||||
for (const typename Range::value_type& elem : seq) {
|
||||
if (idx > 0) {
|
||||
sb << delimiter;
|
||||
}
|
||||
sb << elem;
|
||||
|
||||
++idx;
|
||||
}
|
||||
return sb.Release();
|
||||
}
|
||||
|
||||
template <typename Range, typename Functor>
|
||||
std::string StrJoin(const Range& seq,
|
||||
absl::string_view delimiter,
|
||||
const Functor& fn) {
|
||||
rtc::StringBuilder sb;
|
||||
int idx = 0;
|
||||
|
||||
for (const typename Range::value_type& elem : seq) {
|
||||
if (idx > 0) {
|
||||
sb << delimiter;
|
||||
}
|
||||
fn(sb, elem);
|
||||
|
||||
++idx;
|
||||
}
|
||||
return sb.Release();
|
||||
}
|
||||
|
||||
} // namespace dcsctp
|
||||
|
||||
#endif // NET_DCSCTP_COMMON_STR_JOIN_H_
|
||||
45
net/dcsctp/common/str_join_test.cc
Normal file
45
net/dcsctp/common/str_join_test.cc
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include "net/dcsctp/common/str_join.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "test/gmock.h"
|
||||
|
||||
namespace dcsctp {
|
||||
namespace {
|
||||
|
||||
TEST(StrJoinTest, CanJoinStringsFromVector) {
|
||||
std::vector<std::string> strings = {"Hello", "World"};
|
||||
std::string s = StrJoin(strings, " ");
|
||||
EXPECT_EQ(s, "Hello World");
|
||||
}
|
||||
|
||||
TEST(StrJoinTest, CanJoinNumbersFromArray) {
|
||||
std::array<int, 3> numbers = {1, 2, 3};
|
||||
std::string s = StrJoin(numbers, ",");
|
||||
EXPECT_EQ(s, "1,2,3");
|
||||
}
|
||||
|
||||
TEST(StrJoinTest, CanFormatElementsWhileJoining) {
|
||||
std::vector<std::pair<std::string, std::string>> pairs = {
|
||||
{"hello", "world"}, {"foo", "bar"}, {"fum", "gazonk"}};
|
||||
std::string s = StrJoin(pairs, ",",
|
||||
[&](rtc::StringBuilder& sb,
|
||||
const std::pair<std::string, std::string>& p) {
|
||||
sb << p.first << "=" << p.second;
|
||||
});
|
||||
EXPECT_EQ(s, "hello=world,foo=bar,fum=gazonk");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace dcsctp
|
||||
Loading…
x
Reference in New Issue
Block a user