LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/base - safe_compare.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 24 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 270 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : inline typename std::make_unsigned<T>::type MakeUnsigned(T a) {
      72           0 :   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           0 : inline bool Cmp(T1 a, T2 b) {
      82           0 :   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           0 : inline bool Cmp(T1 a, T2 b) {
      94           0 :   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           0 : inline bool Cmp(T1 a, T2 b) {
     106           0 :   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           0 : inline bool Cmp(T1 a, T2 b) {
     118           0 :   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           0 : inline bool Cmp(T1 a, T2 b) {
     130           0 :   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           0 : RTC_SAFECMP_MAKE_OP(EqOp, ==)
     141           0 : RTC_SAFECMP_MAKE_OP(NeOp, !=)
     142           0 : RTC_SAFECMP_MAKE_OP(LtOp, <)
     143           0 : RTC_SAFECMP_MAKE_OP(LeOp, <=)
     144           0 : RTC_SAFECMP_MAKE_OP(GtOp, >)
     145           0 : RTC_SAFECMP_MAKE_OP(GeOp, >=)
     146             : #undef RTC_SAFECMP_MAKE_OP
     147             : 
     148             : // Determines if the given type is an enum that converts implicitly to
     149             : // an integral type.
     150             : template <typename T>
     151             : struct IsIntEnum {
     152             :  private:
     153             :   // This overload is used if the type is an enum, and unary plus
     154             :   // compiles and turns it into an integral type.
     155             :   template <typename X,
     156             :             typename std::enable_if<
     157             :                 std::is_enum<X>::value &&
     158             :                 std::is_integral<decltype(+std::declval<X>())>::value>::type* =
     159             :                 nullptr>
     160             :   static int Test(int);
     161             : 
     162             :   // Otherwise, this overload is used.
     163             :   template <typename>
     164             :   static char Test(...);
     165             : 
     166             :  public:
     167             :   static constexpr bool value =
     168             :       std::is_same<decltype(Test<typename std::remove_reference<T>::type>(0)),
     169             :                    int>::value;
     170             : };
     171             : 
     172             : // Determines if the given type is integral, or an enum that
     173             : // converts implicitly to an integral type.
     174             : template <typename T>
     175             : struct IsIntlike {
     176             :  private:
     177             :   using X = typename std::remove_reference<T>::type;
     178             : 
     179             :  public:
     180             :   static constexpr bool value =
     181             :       std::is_integral<X>::value || IsIntEnum<X>::value;
     182             : };
     183             : 
     184             : namespace test_enum_intlike {
     185             : 
     186             : enum E1 { e1 };
     187             : enum { e2 };
     188             : enum class E3 { e3 };
     189             : struct S {};
     190             : 
     191             : static_assert(IsIntEnum<E1>::value, "");
     192             : static_assert(IsIntEnum<decltype(e2)>::value, "");
     193             : static_assert(!IsIntEnum<E3>::value, "");
     194             : static_assert(!IsIntEnum<int>::value, "");
     195             : static_assert(!IsIntEnum<float>::value, "");
     196             : static_assert(!IsIntEnum<S>::value, "");
     197             : 
     198             : static_assert(IsIntlike<E1>::value, "");
     199             : static_assert(IsIntlike<decltype(e2)>::value, "");
     200             : static_assert(!IsIntlike<E3>::value, "");
     201             : static_assert(IsIntlike<int>::value, "");
     202             : static_assert(!IsIntlike<float>::value, "");
     203             : static_assert(!IsIntlike<S>::value, "");
     204             : 
     205             : }  // test_enum_intlike
     206             : }  // namespace safe_cmp_impl
     207             : 
     208             : #define RTC_SAFECMP_MAKE_FUN(name)                                      \
     209             :   template <typename T1, typename T2,                                   \
     210             :             typename std::enable_if<                                    \
     211             :                 safe_cmp_impl::IsIntlike<T1>::value &&                  \
     212             :                 safe_cmp_impl::IsIntlike<T2>::value>::type* = nullptr>  \
     213             :   inline bool name(T1 a, T2 b) {                                        \
     214             :     /* Unary plus here turns enums into real integral types. */         \
     215             :     return safe_cmp_impl::Cmp<safe_cmp_impl::name##Op>(+a, +b);         \
     216             :   }                                                                     \
     217             :   template <typename T1, typename T2,                                   \
     218             :             typename std::enable_if<                                    \
     219             :                 !safe_cmp_impl::IsIntlike<T1>::value ||                 \
     220             :                 !safe_cmp_impl::IsIntlike<T2>::value>::type* = nullptr> \
     221             :   inline bool name(T1&& a, T2&& b) {                                    \
     222             :     return safe_cmp_impl::name##Op::Op(a, b);                           \
     223             :   }
     224           0 : RTC_SAFECMP_MAKE_FUN(Eq)
     225           0 : RTC_SAFECMP_MAKE_FUN(Ne)
     226           0 : RTC_SAFECMP_MAKE_FUN(Lt)
     227           0 : RTC_SAFECMP_MAKE_FUN(Le)
     228           0 : RTC_SAFECMP_MAKE_FUN(Gt)
     229           0 : RTC_SAFECMP_MAKE_FUN(Ge)
     230             : #undef RTC_SAFECMP_MAKE_FUN
     231             : 
     232             : }  // namespace safe_cmp
     233             : }  // namespace rtc
     234             : 
     235             : #endif  // WEBRTC_BASE_SAFE_COMPARE_H_

Generated by: LCOV version 1.13