From 9861f960c320f9a35bdb2c795c068a4faed34862 Mon Sep 17 00:00:00 2001 From: Victor Boivie Date: Tue, 13 Apr 2021 14:52:53 +0200 Subject: [PATCH] dcsctp: Add operators on TimeMs and DurationMs To be able to use them type-safely, they should support native operators (e.g. adding a time and a duration, or subtracting two time values), as the alternative is to manage them as numbers. Yes, this makes them behave a bit like absl::Time/absl::Duration. Bug: webrtc:12614 Change-Id: I4dea12e33698a46e71fb549f44c06f2f381c9201 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215143 Reviewed-by: Tommi Commit-Queue: Victor Boivie Cr-Commit-Position: refs/heads/master@{#33725} --- net/dcsctp/public/BUILD.gn | 6 ++- net/dcsctp/public/types.h | 72 +++++++++++++++++++++++++++++++-- net/dcsctp/public/types_test.cc | 50 +++++++++++++++++++++++ net/dcsctp/timer/fake_timeout.h | 2 +- net/dcsctp/timer/timer_test.cc | 2 +- 5 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 net/dcsctp/public/types_test.cc diff --git a/net/dcsctp/public/BUILD.gn b/net/dcsctp/public/BUILD.gn index 863b90378b..dc23df673a 100644 --- a/net/dcsctp/public/BUILD.gn +++ b/net/dcsctp/public/BUILD.gn @@ -46,11 +46,15 @@ if (rtc_include_tests) { deps = [ ":strong_alias", + ":types", "../../../rtc_base:checks", "../../../rtc_base:gunit_helpers", "../../../rtc_base:rtc_base_approved", "../../../test:test_support", ] - sources = [ "strong_alias_test.cc" ] + sources = [ + "strong_alias_test.cc", + "types_test.cc", + ] } } diff --git a/net/dcsctp/public/types.h b/net/dcsctp/public/types.h index 0b22fa8b41..b87fd4e79a 100644 --- a/net/dcsctp/public/types.h +++ b/net/dcsctp/public/types.h @@ -11,6 +11,8 @@ #ifndef NET_DCSCTP_PUBLIC_TYPES_H_ #define NET_DCSCTP_PUBLIC_TYPES_H_ +#include + #include "net/dcsctp/public/strong_alias.h" namespace dcsctp { @@ -29,10 +31,74 @@ using TimeoutID = StrongAlias; using IsUnordered = StrongAlias; // Duration, as milliseconds. Overflows after 24 days. -using DurationMs = StrongAlias; +class DurationMs : public StrongAlias { + public: + constexpr explicit DurationMs(const UnderlyingType& v) + : StrongAlias(v) {} -// Current time, in milliseconds since a client-defined epoch.ยด -using TimeMs = StrongAlias; + // Convenience methods for working with time. + constexpr DurationMs& operator+=(DurationMs d) { + value_ += d.value_; + return *this; + } + constexpr DurationMs& operator-=(DurationMs d) { + value_ -= d.value_; + return *this; + } + template + constexpr DurationMs& operator*=(T factor) { + value_ *= factor; + return *this; + } +}; + +constexpr inline DurationMs operator+(DurationMs lhs, DurationMs rhs) { + return lhs += rhs; +} +constexpr inline DurationMs operator-(DurationMs lhs, DurationMs rhs) { + return lhs -= rhs; +} +template +constexpr inline DurationMs operator*(DurationMs lhs, T rhs) { + return lhs *= rhs; +} +template +constexpr inline DurationMs operator*(T lhs, DurationMs rhs) { + return rhs *= lhs; +} +constexpr inline int32_t operator/(DurationMs lhs, DurationMs rhs) { + return lhs.value() / rhs.value(); +} + +// Represents time, in milliseconds since a client-defined epoch. +class TimeMs : public StrongAlias { + public: + constexpr explicit TimeMs(const UnderlyingType& v) + : StrongAlias(v) {} + + // Convenience methods for working with time. + constexpr TimeMs& operator+=(DurationMs d) { + value_ += *d; + return *this; + } + constexpr TimeMs& operator-=(DurationMs d) { + value_ -= *d; + return *this; + } +}; + +constexpr inline TimeMs operator+(TimeMs lhs, DurationMs rhs) { + return lhs += rhs; +} +constexpr inline TimeMs operator+(DurationMs lhs, TimeMs rhs) { + return rhs += lhs; +} +constexpr inline TimeMs operator-(TimeMs lhs, DurationMs rhs) { + return lhs -= rhs; +} +constexpr inline DurationMs operator-(TimeMs lhs, TimeMs rhs) { + return DurationMs(*lhs - *rhs); +} } // namespace dcsctp diff --git a/net/dcsctp/public/types_test.cc b/net/dcsctp/public/types_test.cc new file mode 100644 index 0000000000..d3d1240751 --- /dev/null +++ b/net/dcsctp/public/types_test.cc @@ -0,0 +1,50 @@ +/* + * 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/public/types.h" + +#include "rtc_base/gunit.h" +#include "test/gmock.h" + +namespace dcsctp { +namespace { + +TEST(TypesTest, DurationOperators) { + DurationMs d1(10); + DurationMs d2(25); + EXPECT_EQ(d1 + d2, DurationMs(35)); + EXPECT_EQ(d2 - d1, DurationMs(15)); + + d1 += d2; + EXPECT_EQ(d1, DurationMs(35)); + + d1 -= DurationMs(5); + EXPECT_EQ(d1, DurationMs(30)); + + d1 *= 1.5; + EXPECT_EQ(d1, DurationMs(45)); + + EXPECT_EQ(DurationMs(10) * 2, DurationMs(20)); +} + +TEST(TypesTest, TimeOperators) { + EXPECT_EQ(TimeMs(250) + DurationMs(100), TimeMs(350)); + EXPECT_EQ(DurationMs(250) + TimeMs(100), TimeMs(350)); + EXPECT_EQ(TimeMs(250) - DurationMs(100), TimeMs(150)); + EXPECT_EQ(TimeMs(250) - TimeMs(100), DurationMs(150)); + + TimeMs t1(150); + t1 -= DurationMs(50); + EXPECT_EQ(t1, TimeMs(100)); + t1 += DurationMs(200); + EXPECT_EQ(t1, TimeMs(300)); +} + +} // namespace +} // namespace dcsctp diff --git a/net/dcsctp/timer/fake_timeout.h b/net/dcsctp/timer/fake_timeout.h index 06e3085a5b..265b34edfa 100644 --- a/net/dcsctp/timer/fake_timeout.h +++ b/net/dcsctp/timer/fake_timeout.h @@ -33,7 +33,7 @@ class FakeTimeout : public Timeout { void Start(DurationMs duration_ms, TimeoutID timeout_id) override { timeout_id_ = timeout_id; - expiry_ = TimeMs(*get_time_() + *duration_ms); + expiry_ = get_time_() + duration_ms; } void Stop() override { expiry_ = InfiniteFuture(); } diff --git a/net/dcsctp/timer/timer_test.cc b/net/dcsctp/timer/timer_test.cc index 263f535dab..9533234895 100644 --- a/net/dcsctp/timer/timer_test.cc +++ b/net/dcsctp/timer/timer_test.cc @@ -30,7 +30,7 @@ class TimerTest : public testing::Test { } void AdvanceTimeAndRunTimers(DurationMs duration) { - now_ = TimeMs(*now_ + *duration); + now_ = now_ + duration; for (TimeoutID timeout_id : timeout_manager_.RunTimers()) { manager_.HandleTimeout(timeout_id);