• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 RTC_BASE_NUMERICS_MOD_OPS_H_
12 #define RTC_BASE_NUMERICS_MOD_OPS_H_
13 
14 #include <algorithm>
15 #include <type_traits>
16 
17 #include "rtc_base/checks.h"
18 
19 namespace webrtc {
20 
21 template <unsigned long M>                                    // NOLINT
Add(unsigned long a,unsigned long b)22 inline unsigned long Add(unsigned long a, unsigned long b) {  // NOLINT
23   RTC_DCHECK_LT(a, M);
24   unsigned long t = M - b % M;  // NOLINT
25   unsigned long res = a - t;    // NOLINT
26   if (t > a)
27     return res + M;
28   return res;
29 }
30 
31 template <unsigned long M>                                         // NOLINT
Subtract(unsigned long a,unsigned long b)32 inline unsigned long Subtract(unsigned long a, unsigned long b) {  // NOLINT
33   RTC_DCHECK_LT(a, M);
34   unsigned long sub = b % M;  // NOLINT
35   if (a < sub)
36     return M - (sub - a);
37   return a - sub;
38 }
39 
40 // Calculates the forward difference between two wrapping numbers.
41 //
42 // Example:
43 // uint8_t x = 253;
44 // uint8_t y = 2;
45 //
46 // ForwardDiff(x, y) == 5
47 //
48 //   252   253   254   255    0     1     2     3
49 // #################################################
50 // |     |  x  |     |     |     |     |  y  |     |
51 // #################################################
52 //          |----->----->----->----->----->
53 //
54 // ForwardDiff(y, x) == 251
55 //
56 //   252   253   254   255    0     1     2     3
57 // #################################################
58 // |     |  x  |     |     |     |     |  y  |     |
59 // #################################################
60 // -->----->                              |----->---
61 //
62 // If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the
63 // largest value representable by T.
64 template <typename T, T M>
ForwardDiff(T a,T b)65 inline typename std::enable_if<(M > 0), T>::type ForwardDiff(T a, T b) {
66   static_assert(std::is_unsigned<T>::value,
67                 "Type must be an unsigned integer.");
68   RTC_DCHECK_LT(a, M);
69   RTC_DCHECK_LT(b, M);
70   return a <= b ? b - a : M - (a - b);
71 }
72 
73 template <typename T, T M>
ForwardDiff(T a,T b)74 inline typename std::enable_if<(M == 0), T>::type ForwardDiff(T a, T b) {
75   static_assert(std::is_unsigned<T>::value,
76                 "Type must be an unsigned integer.");
77   return b - a;
78 }
79 
80 template <typename T>
ForwardDiff(T a,T b)81 inline T ForwardDiff(T a, T b) {
82   return ForwardDiff<T, 0>(a, b);
83 }
84 
85 // Calculates the reverse difference between two wrapping numbers.
86 //
87 // Example:
88 // uint8_t x = 253;
89 // uint8_t y = 2;
90 //
91 // ReverseDiff(y, x) == 5
92 //
93 //   252   253   254   255    0     1     2     3
94 // #################################################
95 // |     |  x  |     |     |     |     |  y  |     |
96 // #################################################
97 //          <-----<-----<-----<-----<-----|
98 //
99 // ReverseDiff(x, y) == 251
100 //
101 //   252   253   254   255    0     1     2     3
102 // #################################################
103 // |     |  x  |     |     |     |     |  y  |     |
104 // #################################################
105 // ---<-----|                             |<-----<--
106 //
107 // If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the
108 // largest value representable by T.
109 template <typename T, T M>
ReverseDiff(T a,T b)110 inline typename std::enable_if<(M > 0), T>::type ReverseDiff(T a, T b) {
111   static_assert(std::is_unsigned<T>::value,
112                 "Type must be an unsigned integer.");
113   RTC_DCHECK_LT(a, M);
114   RTC_DCHECK_LT(b, M);
115   return b <= a ? a - b : M - (b - a);
116 }
117 
118 template <typename T, T M>
ReverseDiff(T a,T b)119 inline typename std::enable_if<(M == 0), T>::type ReverseDiff(T a, T b) {
120   static_assert(std::is_unsigned<T>::value,
121                 "Type must be an unsigned integer.");
122   return a - b;
123 }
124 
125 template <typename T>
ReverseDiff(T a,T b)126 inline T ReverseDiff(T a, T b) {
127   return ReverseDiff<T, 0>(a, b);
128 }
129 
130 // Calculates the minimum distance between to wrapping numbers.
131 //
132 // The minimum distance is defined as min(ForwardDiff(a, b), ReverseDiff(a, b))
133 template <typename T, T M = 0>
MinDiff(T a,T b)134 inline T MinDiff(T a, T b) {
135   static_assert(std::is_unsigned<T>::value,
136                 "Type must be an unsigned integer.");
137   return std::min(ForwardDiff<T, M>(a, b), ReverseDiff<T, M>(a, b));
138 }
139 
140 }  // namespace webrtc
141 
142 #endif  // RTC_BASE_NUMERICS_MOD_OPS_H_
143