tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

safe_math_shared_impl.h (7719B)


      1 // Copyright 2017 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
      6 #define BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
      7 
      8 #include <stddef.h>
      9 #include <stdint.h>
     10 
     11 #include <cassert>
     12 #include <climits>
     13 #include <cmath>
     14 #include <cstdlib>
     15 #include <limits>
     16 #include <type_traits>
     17 
     18 #include "base/numerics/safe_conversions.h"
     19 #include "build/build_config.h"
     20 
     21 #if BUILDFLAG(IS_ASMJS)
     22 // Optimized safe math instructions are incompatible with asmjs.
     23 #define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
     24 // Where available use builtin math overflow support on Clang and GCC.
     25 #elif !defined(__native_client__) &&                       \
     26    ((defined(__clang__) &&                                \
     27      ((__clang_major__ > 3) ||                            \
     28       (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
     29     (defined(__GNUC__) && __GNUC__ >= 5))
     30 #include "base/numerics/safe_math_clang_gcc_impl.h"
     31 #define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
     32 #else
     33 #define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
     34 #endif
     35 
     36 namespace base {
     37 namespace internal {
     38 
     39 // These are the non-functioning boilerplate implementations of the optimized
     40 // safe math routines.
     41 #if !BASE_HAS_OPTIMIZED_SAFE_MATH
     42 template <typename T, typename U>
     43 struct CheckedAddFastOp {
     44  static const bool is_supported = false;
     45  template <typename V>
     46  static constexpr bool Do(T, U, V*) {
     47    // Force a compile failure if instantiated.
     48    return CheckOnFailure::template HandleFailure<bool>();
     49  }
     50 };
     51 
     52 template <typename T, typename U>
     53 struct CheckedSubFastOp {
     54  static const bool is_supported = false;
     55  template <typename V>
     56  static constexpr bool Do(T, U, V*) {
     57    // Force a compile failure if instantiated.
     58    return CheckOnFailure::template HandleFailure<bool>();
     59  }
     60 };
     61 
     62 template <typename T, typename U>
     63 struct CheckedMulFastOp {
     64  static const bool is_supported = false;
     65  template <typename V>
     66  static constexpr bool Do(T, U, V*) {
     67    // Force a compile failure if instantiated.
     68    return CheckOnFailure::template HandleFailure<bool>();
     69  }
     70 };
     71 
     72 template <typename T, typename U>
     73 struct ClampedAddFastOp {
     74  static const bool is_supported = false;
     75  template <typename V>
     76  static constexpr V Do(T, U) {
     77    // Force a compile failure if instantiated.
     78    return CheckOnFailure::template HandleFailure<V>();
     79  }
     80 };
     81 
     82 template <typename T, typename U>
     83 struct ClampedSubFastOp {
     84  static const bool is_supported = false;
     85  template <typename V>
     86  static constexpr V Do(T, U) {
     87    // Force a compile failure if instantiated.
     88    return CheckOnFailure::template HandleFailure<V>();
     89  }
     90 };
     91 
     92 template <typename T, typename U>
     93 struct ClampedMulFastOp {
     94  static const bool is_supported = false;
     95  template <typename V>
     96  static constexpr V Do(T, U) {
     97    // Force a compile failure if instantiated.
     98    return CheckOnFailure::template HandleFailure<V>();
     99  }
    100 };
    101 
    102 template <typename T>
    103 struct ClampedNegFastOp {
    104  static const bool is_supported = false;
    105  static constexpr T Do(T) {
    106    // Force a compile failure if instantiated.
    107    return CheckOnFailure::template HandleFailure<T>();
    108  }
    109 };
    110 #endif  // BASE_HAS_OPTIMIZED_SAFE_MATH
    111 #undef BASE_HAS_OPTIMIZED_SAFE_MATH
    112 
    113 // This is used for UnsignedAbs, where we need to support floating-point
    114 // template instantiations even though we don't actually support the operations.
    115 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
    116 // so the float versions will not compile.
    117 template <typename Numeric,
    118          bool IsInteger = std::is_integral_v<Numeric>,
    119          bool IsFloat = std::is_floating_point_v<Numeric>>
    120 struct UnsignedOrFloatForSize;
    121 
    122 template <typename Numeric>
    123 struct UnsignedOrFloatForSize<Numeric, true, false> {
    124  using type = typename std::make_unsigned<Numeric>::type;
    125 };
    126 
    127 template <typename Numeric>
    128 struct UnsignedOrFloatForSize<Numeric, false, true> {
    129  using type = Numeric;
    130 };
    131 
    132 // Wrap the unary operations to allow SFINAE when instantiating integrals versus
    133 // floating points. These don't perform any overflow checking. Rather, they
    134 // exhibit well-defined overflow semantics and rely on the caller to detect
    135 // if an overflow occurred.
    136 
    137 template <typename T, std::enable_if_t<std::is_integral_v<T>>* = nullptr>
    138 constexpr T NegateWrapper(T value) {
    139  using UnsignedT = typename std::make_unsigned<T>::type;
    140  // This will compile to a NEG on Intel, and is normal negation on ARM.
    141  return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
    142 }
    143 
    144 template <typename T, std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
    145 constexpr T NegateWrapper(T value) {
    146  return -value;
    147 }
    148 
    149 template <typename T, std::enable_if_t<std::is_integral_v<T>>* = nullptr>
    150 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
    151  return ~value;
    152 }
    153 
    154 template <typename T, std::enable_if_t<std::is_integral_v<T>>* = nullptr>
    155 constexpr T AbsWrapper(T value) {
    156  return static_cast<T>(SafeUnsignedAbs(value));
    157 }
    158 
    159 template <typename T, std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
    160 constexpr T AbsWrapper(T value) {
    161  return value < 0 ? -value : value;
    162 }
    163 
    164 template <template <typename, typename, typename> class M,
    165          typename L,
    166          typename R>
    167 struct MathWrapper {
    168  using math = M<typename UnderlyingType<L>::type,
    169                 typename UnderlyingType<R>::type,
    170                 void>;
    171  using type = typename math::result_type;
    172 };
    173 
    174 // The following macros are just boilerplate for the standard arithmetic
    175 // operator overloads and variadic function templates. A macro isn't the nicest
    176 // solution, but it beats rewriting these over and over again.
    177 #define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)       \
    178  template <typename L, typename R, typename... Args>                   \
    179  constexpr auto CL_ABBR##OP_NAME(const L lhs, const R rhs,             \
    180                                  const Args... args) {                 \
    181    return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
    182                                                              args...); \
    183  }
    184 
    185 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
    186  /* Binary arithmetic operator for all CLASS##Numeric operations. */          \
    187  template <typename L, typename R,                                            \
    188            std::enable_if_t<Is##CLASS##Op<L, R>::value>* = nullptr>           \
    189  constexpr CLASS##Numeric<                                                    \
    190      typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type>                    \
    191  operator OP(const L lhs, const R rhs) {                                      \
    192    return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs,      \
    193                                                                     rhs);     \
    194  }                                                                            \
    195  /* Assignment arithmetic operator implementation from CLASS##Numeric. */     \
    196  template <typename L>                                                        \
    197  template <typename R>                                                        \
    198  constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP(             \
    199      const R rhs) {                                                           \
    200    return MathOp<CLASS##OP_NAME##Op>(rhs);                                    \
    201  }                                                                            \
    202  /* Variadic arithmetic functions that return CLASS##Numeric. */              \
    203  BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
    204 
    205 }  // namespace internal
    206 }  // namespace base
    207 
    208 #endif  // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_