OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2016 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 // This file defines six functions: | 11 // This file defines six constexpr functions: |
12 // | 12 // |
13 // rtc::safe_cmp::Eq // == | 13 // rtc::safe_cmp::Eq // == |
14 // rtc::safe_cmp::Ne // != | 14 // rtc::safe_cmp::Ne // != |
15 // rtc::safe_cmp::Lt // < | 15 // rtc::safe_cmp::Lt // < |
16 // rtc::safe_cmp::Le // <= | 16 // rtc::safe_cmp::Le // <= |
17 // rtc::safe_cmp::Gt // > | 17 // rtc::safe_cmp::Gt // > |
18 // rtc::safe_cmp::Ge // >= | 18 // rtc::safe_cmp::Ge // >= |
19 // | 19 // |
20 // They each accept two arguments of arbitrary types, and in almost all cases, | 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 | 21 // they simply call the appropriate comparison operator. However, if both |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 // than T1 (and no larger than the larger of T2 and int*, for performance | 63 // than T1 (and no larger than the larger of T2 and int*, for performance |
64 // reasons); and if there is such a type, LargerInt<T1, T2>::type is an alias | 64 // reasons); and if there is such a type, LargerInt<T1, T2>::type is an alias |
65 // for it. | 65 // for it. |
66 template <typename T1, typename T2> | 66 template <typename T1, typename T2> |
67 struct LargerInt | 67 struct LargerInt |
68 : LargerIntImpl<sizeof(T1) < sizeof(T2) || sizeof(T1) < sizeof(int*) | 68 : LargerIntImpl<sizeof(T1) < sizeof(T2) || sizeof(T1) < sizeof(int*) |
69 ? sizeof(T1) | 69 ? sizeof(T1) |
70 : 0> {}; | 70 : 0> {}; |
71 | 71 |
72 template <typename T> | 72 template <typename T> |
73 inline typename std::make_unsigned<T>::type MakeUnsigned(T a) { | 73 constexpr typename std::make_unsigned<T>::type MakeUnsigned(T a) { |
74 return static_cast<typename std::make_unsigned<T>::type>(a); | 74 return static_cast<typename std::make_unsigned<T>::type>(a); |
75 } | 75 } |
76 | 76 |
77 // Overload for when both T1 and T2 have the same signedness. | 77 // Overload for when both T1 and T2 have the same signedness. |
78 template <typename Op, | 78 template <typename Op, |
79 typename T1, | 79 typename T1, |
80 typename T2, | 80 typename T2, |
81 typename std::enable_if<std::is_signed<T1>::value == | 81 typename std::enable_if<std::is_signed<T1>::value == |
82 std::is_signed<T2>::value>::type* = nullptr> | 82 std::is_signed<T2>::value>::type* = nullptr> |
83 inline bool Cmp(T1 a, T2 b) { | 83 constexpr bool Cmp(T1 a, T2 b) { |
84 return Op::Op(a, b); | 84 return Op::Op(a, b); |
85 } | 85 } |
86 | 86 |
87 // Overload for signed - unsigned comparison that can be promoted to a bigger | 87 // Overload for signed - unsigned comparison that can be promoted to a bigger |
88 // signed type. | 88 // signed type. |
89 template <typename Op, | 89 template <typename Op, |
90 typename T1, | 90 typename T1, |
91 typename T2, | 91 typename T2, |
92 typename std::enable_if<std::is_signed<T1>::value && | 92 typename std::enable_if<std::is_signed<T1>::value && |
93 std::is_unsigned<T2>::value && | 93 std::is_unsigned<T2>::value && |
94 LargerInt<T2, T1>::value>::type* = nullptr> | 94 LargerInt<T2, T1>::value>::type* = nullptr> |
95 inline bool Cmp(T1 a, T2 b) { | 95 constexpr bool Cmp(T1 a, T2 b) { |
96 return Op::Op(a, static_cast<typename LargerInt<T2, T1>::type>(b)); | 96 return Op::Op(a, static_cast<typename LargerInt<T2, T1>::type>(b)); |
97 } | 97 } |
98 | 98 |
99 // Overload for unsigned - signed comparison that can be promoted to a bigger | 99 // Overload for unsigned - signed comparison that can be promoted to a bigger |
100 // signed type. | 100 // signed type. |
101 template <typename Op, | 101 template <typename Op, |
102 typename T1, | 102 typename T1, |
103 typename T2, | 103 typename T2, |
104 typename std::enable_if<std::is_unsigned<T1>::value && | 104 typename std::enable_if<std::is_unsigned<T1>::value && |
105 std::is_signed<T2>::value && | 105 std::is_signed<T2>::value && |
106 LargerInt<T1, T2>::value>::type* = nullptr> | 106 LargerInt<T1, T2>::value>::type* = nullptr> |
107 inline bool Cmp(T1 a, T2 b) { | 107 constexpr bool Cmp(T1 a, T2 b) { |
108 return Op::Op(static_cast<typename LargerInt<T1, T2>::type>(a), b); | 108 return Op::Op(static_cast<typename LargerInt<T1, T2>::type>(a), b); |
109 } | 109 } |
110 | 110 |
111 // Overload for signed - unsigned comparison that can't be promoted to a bigger | 111 // Overload for signed - unsigned comparison that can't be promoted to a bigger |
112 // signed type. | 112 // signed type. |
113 template <typename Op, | 113 template <typename Op, |
114 typename T1, | 114 typename T1, |
115 typename T2, | 115 typename T2, |
116 typename std::enable_if<std::is_signed<T1>::value && | 116 typename std::enable_if<std::is_signed<T1>::value && |
117 std::is_unsigned<T2>::value && | 117 std::is_unsigned<T2>::value && |
118 !LargerInt<T2, T1>::value>::type* = nullptr> | 118 !LargerInt<T2, T1>::value>::type* = nullptr> |
119 inline bool Cmp(T1 a, T2 b) { | 119 constexpr bool Cmp(T1 a, T2 b) { |
120 return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b); | 120 return a < 0 ? Op::Op(-1, 0) : Op::Op(safe_cmp_impl::MakeUnsigned(a), b); |
121 } | 121 } |
122 | 122 |
123 // Overload for unsigned - signed comparison that can't be promoted to a bigger | 123 // Overload for unsigned - signed comparison that can't be promoted to a bigger |
124 // signed type. | 124 // signed type. |
125 template <typename Op, | 125 template <typename Op, |
126 typename T1, | 126 typename T1, |
127 typename T2, | 127 typename T2, |
128 typename std::enable_if<std::is_unsigned<T1>::value && | 128 typename std::enable_if<std::is_unsigned<T1>::value && |
129 std::is_signed<T2>::value && | 129 std::is_signed<T2>::value && |
130 !LargerInt<T1, T2>::value>::type* = nullptr> | 130 !LargerInt<T1, T2>::value>::type* = nullptr> |
131 inline bool Cmp(T1 a, T2 b) { | 131 constexpr bool Cmp(T1 a, T2 b) { |
132 return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b)); | 132 return b < 0 ? Op::Op(0, -1) : Op::Op(a, safe_cmp_impl::MakeUnsigned(b)); |
133 } | 133 } |
134 | 134 |
135 #define RTC_SAFECMP_MAKE_OP(name, op) \ | 135 #define RTC_SAFECMP_MAKE_OP(name, op) \ |
136 struct name { \ | 136 struct name { \ |
137 template <typename T1, typename T2> \ | 137 template <typename T1, typename T2> \ |
138 static constexpr bool Op(T1 a, T2 b) { \ | 138 static constexpr bool Op(T1 a, T2 b) { \ |
139 return a op b; \ | 139 return a op b; \ |
140 } \ | 140 } \ |
141 }; | 141 }; |
142 RTC_SAFECMP_MAKE_OP(EqOp, ==) | 142 RTC_SAFECMP_MAKE_OP(EqOp, ==) |
143 RTC_SAFECMP_MAKE_OP(NeOp, !=) | 143 RTC_SAFECMP_MAKE_OP(NeOp, !=) |
144 RTC_SAFECMP_MAKE_OP(LtOp, <) | 144 RTC_SAFECMP_MAKE_OP(LtOp, <) |
145 RTC_SAFECMP_MAKE_OP(LeOp, <=) | 145 RTC_SAFECMP_MAKE_OP(LeOp, <=) |
146 RTC_SAFECMP_MAKE_OP(GtOp, >) | 146 RTC_SAFECMP_MAKE_OP(GtOp, >) |
147 RTC_SAFECMP_MAKE_OP(GeOp, >=) | 147 RTC_SAFECMP_MAKE_OP(GeOp, >=) |
148 #undef RTC_SAFECMP_MAKE_OP | 148 #undef RTC_SAFECMP_MAKE_OP |
149 | 149 |
150 } // namespace safe_cmp_impl | 150 } // namespace safe_cmp_impl |
151 | 151 |
152 #define RTC_SAFECMP_MAKE_FUN(name) \ | 152 #define RTC_SAFECMP_MAKE_FUN(name) \ |
153 template <typename T1, typename T2, \ | 153 template <typename T1, typename T2> \ |
154 typename std::enable_if<IsIntlike<T1>::value && \ | 154 constexpr \ |
155 IsIntlike<T2>::value>::type* = nullptr> \ | 155 typename std::enable_if<IsIntlike<T1>::value && IsIntlike<T2>::value, \ |
156 inline bool name(T1 a, T2 b) { \ | 156 bool>::type \ |
157 /* Unary plus here turns enums into real integral types. */ \ | 157 name(T1 a, T2 b) { \ |
158 return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b); \ | 158 /* Unary plus here turns enums into real integral types. */ \ |
159 } \ | 159 return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b); \ |
160 template <typename T1, typename T2, \ | 160 } \ |
161 typename std::enable_if<!IsIntlike<T1>::value || \ | 161 template <typename T1, typename T2> \ |
162 !IsIntlike<T2>::value>::type* = nullptr> \ | 162 constexpr \ |
163 inline bool name(T1&& a, T2&& b) { \ | 163 typename std::enable_if<!IsIntlike<T1>::value || !IsIntlike<T2>::value, \ |
164 return safe_cmp_impl::name##Op::Op(a, b); \ | 164 bool>::type \ |
| 165 name(const T1& a, const T2& b) { \ |
| 166 return safe_cmp_impl::name##Op::Op(a, b); \ |
165 } | 167 } |
166 RTC_SAFECMP_MAKE_FUN(Eq) | 168 RTC_SAFECMP_MAKE_FUN(Eq) |
167 RTC_SAFECMP_MAKE_FUN(Ne) | 169 RTC_SAFECMP_MAKE_FUN(Ne) |
168 RTC_SAFECMP_MAKE_FUN(Lt) | 170 RTC_SAFECMP_MAKE_FUN(Lt) |
169 RTC_SAFECMP_MAKE_FUN(Le) | 171 RTC_SAFECMP_MAKE_FUN(Le) |
170 RTC_SAFECMP_MAKE_FUN(Gt) | 172 RTC_SAFECMP_MAKE_FUN(Gt) |
171 RTC_SAFECMP_MAKE_FUN(Ge) | 173 RTC_SAFECMP_MAKE_FUN(Ge) |
172 #undef RTC_SAFECMP_MAKE_FUN | 174 #undef RTC_SAFECMP_MAKE_FUN |
173 | 175 |
174 } // namespace safe_cmp | 176 } // namespace safe_cmp |
175 } // namespace rtc | 177 } // namespace rtc |
176 | 178 |
177 #endif // WEBRTC_BASE_SAFE_COMPARE_H_ | 179 #endif // WEBRTC_BASE_SAFE_COMPARE_H_ |
OLD | NEW |