Index: webrtc/base/safe_compare.h |
diff --git a/webrtc/base/safe_compare.h b/webrtc/base/safe_compare.h |
index 37ddf780c7241a5f55f3e42dc100a7a3a9bb62c2..39fb917a700862312c823bf12febb3dbc0fdf1b7 100644 |
--- a/webrtc/base/safe_compare.h |
+++ b/webrtc/base/safe_compare.h |
@@ -145,26 +145,81 @@ RTC_SAFECMP_MAKE_OP(GtOp, >) |
RTC_SAFECMP_MAKE_OP(GeOp, >=) |
#undef RTC_SAFECMP_MAKE_OP |
+// Determines if the given type is an enum that converts implicitly to |
+// an integral type. |
+template <typename T> |
+struct IsIntEnum { |
+ private: |
+ // This overload is used if the type is an enum, and unary plus |
+ // compiles and turns it into an integral type. |
+ template <typename X, |
+ typename std::enable_if< |
+ std::is_enum<X>::value && |
+ std::is_integral<decltype(+std::declval<X>())>::value>::type* = |
+ nullptr> |
+ static int Test(int); |
+ |
+ // Otherwise, this overload is used. |
+ template <typename> |
+ static char Test(...); |
ossu
2016/11/28 14:14:34
I tried to find an answer to this, and clearly thi
kwiberg-webrtc
2016/11/28 23:20:37
Yes, they can be the same size, but I think they'd
ossu
2016/11/29 10:28:23
Cool beans! Then I'm satisfied. :)
|
+ |
+ public: |
+ static constexpr bool value = |
+ std::is_same<decltype(Test<typename std::remove_reference<T>::type>(0)), |
+ int>::value; |
+}; |
+ |
+// Determines if the given type is integral, or an enum that |
+// converts implicitly to an integral type. |
+template <typename T> |
+struct IsIntlike { |
+ private: |
+ using X = typename std::remove_reference<T>::type; |
+ |
+ public: |
+ static constexpr bool value = |
+ std::is_integral<X>::value || IsIntEnum<X>::value; |
+}; |
+ |
+namespace test_enum_intlike { |
+ |
+enum E1 { e1 }; |
+enum { e2 }; |
+enum class E3 { e3 }; |
+struct S {}; |
+ |
+static_assert(IsIntEnum<E1>::value, ""); |
+static_assert(IsIntEnum<decltype(e2)>::value, ""); |
+static_assert(!IsIntEnum<E3>::value, ""); |
+static_assert(!IsIntEnum<int>::value, ""); |
+static_assert(!IsIntEnum<float>::value, ""); |
+static_assert(!IsIntEnum<S>::value, ""); |
+ |
+static_assert(IsIntlike<E1>::value, ""); |
+static_assert(IsIntlike<decltype(e2)>::value, ""); |
+static_assert(!IsIntlike<E3>::value, ""); |
+static_assert(IsIntlike<int>::value, ""); |
+static_assert(!IsIntlike<float>::value, ""); |
+static_assert(!IsIntlike<S>::value, ""); |
+ |
+} // test_enum_intlike |
} // namespace safe_cmp_impl |
-#define RTC_SAFECMP_MAKE_FUN(name) \ |
- template < \ |
- typename T1, typename T2, \ |
- typename std::enable_if< \ |
- std::is_integral<typename std::remove_reference<T1>::type>::value && \ |
- std::is_integral<typename std::remove_reference<T2>::type>::value>:: \ |
- type* = nullptr> \ |
- inline bool name(T1 a, T2 b) { \ |
- return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(a, b); \ |
- } \ |
- template <typename T1, typename T2, \ |
- typename std::enable_if< \ |
- !std::is_integral< \ |
- typename std::remove_reference<T1>::type>::value || \ |
- !std::is_integral<typename std::remove_reference<T2>::type>:: \ |
- value>::type* = nullptr> \ |
- inline bool name(T1&& a, T2&& b) { \ |
- return safe_cmp_impl::name##Op::Op(a, b); \ |
+#define RTC_SAFECMP_MAKE_FUN(name) \ |
+ template <typename T1, typename T2, \ |
+ typename std::enable_if< \ |
+ safe_cmp_impl::IsIntlike<T1>::value && \ |
+ safe_cmp_impl::IsIntlike<T2>::value>::type* = nullptr> \ |
+ inline bool name(T1 a, T2 b) { \ |
+ /* Unary plus here turns enums into real integral types. */ \ |
+ return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b); \ |
+ } \ |
+ template <typename T1, typename T2, \ |
+ typename std::enable_if< \ |
+ !safe_cmp_impl::IsIntlike<T1>::value || \ |
+ !safe_cmp_impl::IsIntlike<T2>::value>::type* = nullptr> \ |
+ inline bool name(T1&& a, T2&& b) { \ |
+ return safe_cmp_impl::name##Op::Op(a, b); \ |
} |
RTC_SAFECMP_MAKE_FUN(Eq) |
RTC_SAFECMP_MAKE_FUN(Ne) |