1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #ifndef MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
12 #define MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
13
14 #include <limits>
15
16 #include "absl/types/optional.h"
17
18 namespace webrtc {
19
20 template <typename U>
IsNewer(U value,U prev_value)21 inline bool IsNewer(U value, U prev_value) {
22 static_assert(!std::numeric_limits<U>::is_signed, "U must be unsigned");
23 // kBreakpoint is the half-way mark for the type U. For instance, for a
24 // uint16_t it will be 0x8000, and for a uint32_t, it will be 0x8000000.
25 constexpr U kBreakpoint = (std::numeric_limits<U>::max() >> 1) + 1;
26 // Distinguish between elements that are exactly kBreakpoint apart.
27 // If t1>t2 and |t1-t2| = kBreakpoint: IsNewer(t1,t2)=true,
28 // IsNewer(t2,t1)=false
29 // rather than having IsNewer(t1,t2) = IsNewer(t2,t1) = false.
30 if (value - prev_value == kBreakpoint) {
31 return value > prev_value;
32 }
33 return value != prev_value &&
34 static_cast<U>(value - prev_value) < kBreakpoint;
35 }
36
37 // Utility class to unwrap a number to a larger type. The numbers will never be
38 // unwrapped to a negative value.
39 template <typename U>
40 class Unwrapper {
41 static_assert(!std::numeric_limits<U>::is_signed, "U must be unsigned");
42 static_assert(std::numeric_limits<U>::max() <=
43 std::numeric_limits<uint32_t>::max(),
44 "U must not be wider than 32 bits");
45
46 public:
47 // Get the unwrapped value, but don't update the internal state.
UnwrapWithoutUpdate(U value)48 int64_t UnwrapWithoutUpdate(U value) const {
49 if (!last_value_)
50 return value;
51
52 constexpr int64_t kMaxPlusOne =
53 static_cast<int64_t>(std::numeric_limits<U>::max()) + 1;
54
55 U cropped_last = static_cast<U>(*last_value_);
56 int64_t delta = value - cropped_last;
57 if (IsNewer(value, cropped_last)) {
58 if (delta < 0)
59 delta += kMaxPlusOne; // Wrap forwards.
60 } else if (delta > 0 && (*last_value_ + delta - kMaxPlusOne) >= 0) {
61 // If value is older but delta is positive, this is a backwards
62 // wrap-around. However, don't wrap backwards past 0 (unwrapped).
63 delta -= kMaxPlusOne;
64 }
65
66 return *last_value_ + delta;
67 }
68
69 // Only update the internal state to the specified last (unwrapped) value.
UpdateLast(int64_t last_value)70 void UpdateLast(int64_t last_value) { last_value_ = last_value; }
71
72 // Unwrap the value and update the internal state.
Unwrap(U value)73 int64_t Unwrap(U value) {
74 int64_t unwrapped = UnwrapWithoutUpdate(value);
75 UpdateLast(unwrapped);
76 return unwrapped;
77 }
78
79 private:
80 absl::optional<int64_t> last_value_;
81 };
82
83 using SequenceNumberUnwrapper = Unwrapper<uint16_t>;
84 using TimestampUnwrapper = Unwrapper<uint32_t>;
85
86 // NB: Doesn't fulfill strict weak ordering requirements.
87 // Mustn't be used as std::map Compare function.
IsNewerSequenceNumber(uint16_t sequence_number,uint16_t prev_sequence_number)88 inline bool IsNewerSequenceNumber(uint16_t sequence_number,
89 uint16_t prev_sequence_number) {
90 return IsNewer(sequence_number, prev_sequence_number);
91 }
92
93 // NB: Doesn't fulfill strict weak ordering requirements.
94 // Mustn't be used as std::map Compare function.
IsNewerTimestamp(uint32_t timestamp,uint32_t prev_timestamp)95 inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) {
96 return IsNewer(timestamp, prev_timestamp);
97 }
98
LatestSequenceNumber(uint16_t sequence_number1,uint16_t sequence_number2)99 inline uint16_t LatestSequenceNumber(uint16_t sequence_number1,
100 uint16_t sequence_number2) {
101 return IsNewerSequenceNumber(sequence_number1, sequence_number2)
102 ? sequence_number1
103 : sequence_number2;
104 }
105
LatestTimestamp(uint32_t timestamp1,uint32_t timestamp2)106 inline uint32_t LatestTimestamp(uint32_t timestamp1, uint32_t timestamp2) {
107 return IsNewerTimestamp(timestamp1, timestamp2) ? timestamp1 : timestamp2;
108 }
109
110 } // namespace webrtc
111 #endif // MODULES_INCLUDE_MODULE_COMMON_TYPES_PUBLIC_H_
112