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