Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
|
ossu
2016/10/31 16:44:57
I bet the ?: operator could turn into a branch on
kwiberg-webrtc
2016/10/31 21:32:26
Probably. I didn't even try to look at unoptimized
ossu
2016/11/01 15:36:57
Not sure if it matters, but perhaps turning the ?:
kwiberg-webrtc
2016/11/01 16:14:06
No, this is the sort of transformation the compile
ossu
2016/11/01 16:48:07
You think? Yeah, maybe. Granted, if the compiler i
| |
| 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)); | |
|
ossu
2016/11/01 15:36:57
Isn't Op::Op(0, -1) a bad choice here if Op is sup
kwiberg-webrtc
2016/11/01 16:14:06
Op::Op<T1, T2> will accept any two types, and the
ossu
2016/11/01 16:48:07
Ah, right, yes. I somehow expected them to be type
| |
| 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) { \ | |
|
kwiberg-webrtc
2016/10/31 09:16:01
Should I perhaps take a and b by value instead?
ossu
2016/10/31 16:44:57
I'd say const&. That's what comparison operators u
kwiberg-webrtc
2016/10/31 21:32:26
Yes, but this is specifically for built-in integer
ossu
2016/11/01 15:36:57
Ah, right. Yes, pass by value instead!
kwiberg-webrtc
2016/11/01 16:14:06
Done.
| |
| 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) \ | |
|
ossu
2016/10/31 16:44:57
I like fun! Make more fun! :D
kwiberg-webrtc
2016/10/31 21:32:26
Acknowledged.
| |
| 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_ | |
| OLD | NEW |