blob: e3bc38e68e36b3123bed797c6f6b6d601a9b6d0f [file] [log] [blame]
philipel2cb73412016-03-22 10:03:43 +01001/*
2 * Copyright (c) 2016 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 WEBRTC_MODULES_VIDEO_CODING_SEQUENCE_NUMBER_UTIL_H_
12#define WEBRTC_MODULES_VIDEO_CODING_SEQUENCE_NUMBER_UTIL_H_
13
14#include <limits>
15#include <type_traits>
16
Edward Lemurc20978e2017-07-06 19:44:34 +020017#include "webrtc/rtc_base/mod_ops.h"
philipel7956c0f2017-07-26 07:48:15 -070018#include "webrtc/rtc_base/optional.h"
19#include "webrtc/rtc_base/safe_compare.h"
philipel2cb73412016-03-22 10:03:43 +010020
21namespace webrtc {
22
23// Test if the sequence number |a| is ahead or at sequence number |b|.
24//
25// If |M| is an even number and the two sequence numbers are at max distance
26// from each other, then the sequence number with the highest value is
27// considered to be ahead.
28template <typename T, T M>
philipel7956c0f2017-07-26 07:48:15 -070029inline typename std::enable_if<(M > 0), bool>::type AheadOrAt(T a, T b) {
philipel2cb73412016-03-22 10:03:43 +010030 static_assert(std::is_unsigned<T>::value,
31 "Type must be an unsigned integer.");
32 const T maxDist = M / 2;
33 if (!(M & 1) && MinDiff<T, M>(a, b) == maxDist)
34 return b < a;
35 return ForwardDiff<T, M>(b, a) <= maxDist;
36}
37
philipel7956c0f2017-07-26 07:48:15 -070038template <typename T, T M>
39inline typename std::enable_if<(M == 0), bool>::type AheadOrAt(T a, T b) {
philipel2cb73412016-03-22 10:03:43 +010040 static_assert(std::is_unsigned<T>::value,
41 "Type must be an unsigned integer.");
42 const T maxDist = std::numeric_limits<T>::max() / 2 + T(1);
43 if (a - b == maxDist)
44 return b < a;
45 return ForwardDiff(b, a) < maxDist;
46}
47
philipel7956c0f2017-07-26 07:48:15 -070048template <typename T>
49inline bool AheadOrAt(T a, T b) {
50 return AheadOrAt<T, 0>(a, b);
51}
52
philipel2cb73412016-03-22 10:03:43 +010053// Test if the sequence number |a| is ahead of sequence number |b|.
54//
55// If |M| is an even number and the two sequence numbers are at max distance
56// from each other, then the sequence number with the highest value is
57// considered to be ahead.
philipel7956c0f2017-07-26 07:48:15 -070058template <typename T, T M = 0>
philipel2cb73412016-03-22 10:03:43 +010059inline bool AheadOf(T a, T b) {
60 static_assert(std::is_unsigned<T>::value,
61 "Type must be an unsigned integer.");
62 return a != b && AheadOrAt<T, M>(a, b);
63}
64
philipel7956c0f2017-07-26 07:48:15 -070065// Comparator used to compare sequence numbers in a continuous fashion.
66//
67// WARNING! If used to sort sequence numbers of length M then the interval
68// covered by the sequence numbers may not be larger than floor(M/2).
69template <typename T, T M = 0>
70struct AscendingSeqNumComp {
philipel2cb73412016-03-22 10:03:43 +010071 bool operator()(T a, T b) const { return AheadOf<T, M>(a, b); }
72};
73
philipel2cb73412016-03-22 10:03:43 +010074// Comparator used to compare sequence numbers in a continuous fashion.
75//
76// WARNING! If used to sort sequence numbers of length M then the interval
77// covered by the sequence numbers may not be larger than floor(M/2).
78template <typename T, T M = 0>
philipel7956c0f2017-07-26 07:48:15 -070079struct DescendingSeqNumComp {
80 bool operator()(T a, T b) const { return AheadOf<T, M>(b, a); }
philipel2cb73412016-03-22 10:03:43 +010081};
82
philipel7956c0f2017-07-26 07:48:15 -070083// A sequencer number unwrapper where the start value of the unwrapped sequence
84// can be set. The unwrapped value is not allowed to wrap.
philipel2cb73412016-03-22 10:03:43 +010085template <typename T, T M = 0>
philipel7956c0f2017-07-26 07:48:15 -070086class SeqNumUnwrapper {
87 static_assert(
88 std::is_unsigned<T>::value &&
89 rtc::SafeLt(std::numeric_limits<T>::max(),
90 std::numeric_limits<uint64_t>::max()),
91 "Type unwrapped must be an unsigned integer smaller than uint64_t.");
92
93 public:
94 SeqNumUnwrapper() : last_unwrapped_(0) {}
95 explicit SeqNumUnwrapper(uint64_t start_at) : last_unwrapped_(start_at) {}
96
97 uint64_t Unwrap(T value) {
98 if (!last_value_)
99 last_value_.emplace(value);
100
101 uint64_t unwrapped = 0;
102 if (AheadOrAt<T, M>(value, *last_value_)) {
103 unwrapped = last_unwrapped_ + ForwardDiff<T, M>(*last_value_, value);
104 RTC_CHECK_GE(unwrapped, last_unwrapped_);
105 } else {
106 unwrapped = last_unwrapped_ - ReverseDiff<T, M>(*last_value_, value);
107 RTC_CHECK_LT(unwrapped, last_unwrapped_);
108 }
109
110 *last_value_ = value;
111 last_unwrapped_ = unwrapped;
112 return last_unwrapped_;
philipel2cb73412016-03-22 10:03:43 +0100113 }
philipel7956c0f2017-07-26 07:48:15 -0700114
115 private:
116 uint64_t last_unwrapped_;
117 rtc::Optional<T> last_value_;
philipel2cb73412016-03-22 10:03:43 +0100118};
119
120} // namespace webrtc
121
122#endif // WEBRTC_MODULES_VIDEO_CODING_SEQUENCE_NUMBER_UTIL_H_