Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(258)

Side by Side Diff: webrtc/base/safe_compare.h

Issue 2459793002: Let RTC_[D]CHECK_op accept arguments of different signedness (Closed)
Patch Set: by value Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/base/checks.h ('k') | webrtc/base/safe_compare_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 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 // This file defines six functions:
12 //
13 // rtc::safe_cmp::Eq // ==
14 // rtc::safe_cmp::Ne // !=
15 // rtc::safe_cmp::Lt // <
16 // rtc::safe_cmp::Le // <=
17 // rtc::safe_cmp::Gt // >
18 // rtc::safe_cmp::Ge // >=
19 //
20 // They each accept two arguments of arbitrary types, and in almost all cases,
21 // they simply call the appropriate comparison operator. However, if both
22 // arguments are integers, they don't compare them using C++'s quirky rules,
23 // but instead adhere to the true mathematical definitions. It is as if the
24 // arguments were first converted to infinite-range signed integers, and then
25 // compared, although of course nothing expensive like that actually takes
26 // place. In practice, for signed/signed and unsigned/unsigned comparisons and
27 // some mixed-signed comparisons with a compile-time constant, the overhead is
28 // zero; in the remaining cases, it is just a few machine instructions (no
29 // branches).
30
31 #ifndef WEBRTC_BASE_SAFE_COMPARE_H_
32 #define WEBRTC_BASE_SAFE_COMPARE_H_
33
34 #include <stddef.h>
35 #include <stdint.h>
36
37 #include <type_traits>
38 #include <utility>
39
40 namespace rtc {
41 namespace safe_cmp {
42
43 namespace safe_cmp_impl {
44
45 template <size_t N>
46 struct LargerIntImpl : std::false_type {};
47 template <>
48 struct LargerIntImpl<sizeof(int8_t)> : std::true_type {
49 using type = int16_t;
50 };
51 template <>
52 struct LargerIntImpl<sizeof(int16_t)> : std::true_type {
53 using type = int32_t;
54 };
55 template <>
56 struct LargerIntImpl<sizeof(int32_t)> : std::true_type {
57 using type = int64_t;
58 };
59
60 // LargerInt<T1, T2>::value is true iff there's a signed type that's larger
61 // than T1 (and no larger than the larger of T2 and int*, for performance
62 // reasons); and if there is such a type, LargerInt<T1, T2>::type is an alias
63 // for it.
64 template <typename T1, typename T2>
65 struct LargerInt
66 : LargerIntImpl<sizeof(T1) < sizeof(T2) || sizeof(T1) < sizeof(int*)
67 ? sizeof(T1)
68 : 0> {};
69
70 template <typename T>
71 inline typename std::make_unsigned<T>::type MakeUnsigned(T a) {
72 return static_cast<typename std::make_unsigned<T>::type>(a);
73 }
74
75 // Overload for when both T1 and T2 have the same signedness.
76 template <typename Op,
77 typename T1,
78 typename T2,
79 typename std::enable_if<std::is_signed<T1>::value ==
80 std::is_signed<T2>::value>::type* = nullptr>
81 inline bool Cmp(T1 a, T2 b) {
82 return Op::Op(a, b);
83 }
84
85 // Overload for signed - unsigned comparison that can be promoted to a bigger
86 // signed type.
87 template <typename Op,
88 typename T1,
89 typename T2,
90 typename std::enable_if<std::is_signed<T1>::value &&
91 std::is_unsigned<T2>::value &&
92 LargerInt<T2, T1>::value>::type* = nullptr>
93 inline bool Cmp(T1 a, T2 b) {
94 return Op::Op(a, static_cast<typename LargerInt<T2, T1>::type>(b));
95 }
96
97 // Overload for unsigned - signed comparison that can be promoted to a bigger
98 // signed type.
99 template <typename Op,
100 typename T1,
101 typename T2,
102 typename std::enable_if<std::is_unsigned<T1>::value &&
103 std::is_signed<T2>::value &&
104 LargerInt<T1, T2>::value>::type* = nullptr>
105 inline bool Cmp(T1 a, T2 b) {
106 return Op::Op(static_cast<typename LargerInt<T1, T2>::type>(a), b);
107 }
108
109 // Overload for signed - unsigned comparison that can't be promoted to a bigger
110 // signed type.
111 template <typename Op,
112 typename T1,
113 typename T2,
114 typename std::enable_if<std::is_signed<T1>::value &&
115 std::is_unsigned<T2>::value &&
116 !LargerInt<T2, T1>::value>::type* = nullptr>
117 inline bool Cmp(T1 a, T2 b) {
118 return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b);
119 }
120
121 // Overload for unsigned - signed comparison that can't be promoted to a bigger
122 // signed type.
123 template <typename Op,
124 typename T1,
125 typename T2,
126 typename std::enable_if<std::is_unsigned<T1>::value &&
127 std::is_signed<T2>::value &&
128 !LargerInt<T1, T2>::value>::type* = nullptr>
129 inline bool Cmp(T1 a, T2 b) {
130 return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b));
131 }
132
133 #define RTC_SAFECMP_MAKE_OP(name, op) \
134 struct name { \
135 template <typename T1, typename T2> \
136 static constexpr bool Op(T1 a, T2 b) { \
137 return a op b; \
138 } \
139 };
140 RTC_SAFECMP_MAKE_OP(EqOp, ==)
141 RTC_SAFECMP_MAKE_OP(NeOp, !=)
142 RTC_SAFECMP_MAKE_OP(LtOp, <)
143 RTC_SAFECMP_MAKE_OP(LeOp, <=)
144 RTC_SAFECMP_MAKE_OP(GtOp, >)
145 RTC_SAFECMP_MAKE_OP(GeOp, >=)
146 #undef RTC_SAFECMP_MAKE_OP
147
148 } // namespace safe_cmp_impl
149
150 #define RTC_SAFECMP_MAKE_FUN(name) \
151 template < \
152 typename T1, typename T2, \
153 typename std::enable_if< \
154 std::is_integral<typename std::remove_reference<T1>::type>::value && \
155 std::is_integral<typename std::remove_reference<T2>::type>::value>:: \
156 type* = nullptr> \
157 inline bool name(T1 a, T2 b) { \
158 return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(a, b); \
159 } \
160 template <typename T1, typename T2, \
161 typename std::enable_if< \
162 !std::is_integral< \
163 typename std::remove_reference<T1>::type>::value || \
164 !std::is_integral<typename std::remove_reference<T2>::type>:: \
165 value>::type* = nullptr> \
166 inline bool name(T1&& a, T2&& b) { \
167 return safe_cmp_impl::name##Op::Op(a, b); \
168 }
169 RTC_SAFECMP_MAKE_FUN(Eq)
170 RTC_SAFECMP_MAKE_FUN(Ne)
171 RTC_SAFECMP_MAKE_FUN(Lt)
172 RTC_SAFECMP_MAKE_FUN(Le)
173 RTC_SAFECMP_MAKE_FUN(Gt)
174 RTC_SAFECMP_MAKE_FUN(Ge)
175 #undef RTC_SAFECMP_MAKE_FUN
176
177 } // namespace safe_cmp
178 } // namespace rtc
179
180 #endif // WEBRTC_BASE_SAFE_COMPARE_H_
OLDNEW
« no previous file with comments | « webrtc/base/checks.h ('k') | webrtc/base/safe_compare_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698