1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ABSL_RANDOM_INTERNAL_TRAITS_H_ 16 #define ABSL_RANDOM_INTERNAL_TRAITS_H_ 17 18 #include <cstdint> 19 #include <limits> 20 #include <type_traits> 21 22 #include "absl/base/config.h" 23 #include "absl/numeric/bits.h" 24 #include "absl/numeric/int128.h" 25 26 namespace absl { 27 ABSL_NAMESPACE_BEGIN 28 namespace random_internal { 29 30 // random_internal::is_widening_convertible<A, B> 31 // 32 // Returns whether a type A is widening-convertible to a type B. 33 // 34 // A is widening-convertible to B means: 35 // A a = <any number>; 36 // B b = a; 37 // A c = b; 38 // EXPECT_EQ(a, c); 39 template <typename A, typename B> 40 class is_widening_convertible { 41 // As long as there are enough bits in the exact part of a number: 42 // - unsigned can fit in float, signed, unsigned 43 // - signed can fit in float, signed 44 // - float can fit in float 45 // So we define rank to be: 46 // - rank(float) -> 2 47 // - rank(signed) -> 1 48 // - rank(unsigned) -> 0 49 template <class T> rank()50 static constexpr int rank() { 51 return !std::numeric_limits<T>::is_integer + 52 std::numeric_limits<T>::is_signed; 53 } 54 55 public: 56 // If an arithmetic-type B can represent at least as many digits as a type A, 57 // and B belongs to a rank no lower than A, then A can be safely represented 58 // by B through a widening-conversion. 59 static constexpr bool value = 60 std::numeric_limits<A>::digits <= std::numeric_limits<B>::digits && 61 rank<A>() <= rank<B>(); 62 }; 63 64 template <typename T> 65 struct IsIntegral : std::is_integral<T> {}; 66 template <> 67 struct IsIntegral<absl::int128> : std::true_type {}; 68 template <> 69 struct IsIntegral<absl::uint128> : std::true_type {}; 70 71 template <typename T> 72 struct MakeUnsigned : std::make_unsigned<T> {}; 73 template <> 74 struct MakeUnsigned<absl::int128> { 75 using type = absl::uint128; 76 }; 77 template <> 78 struct MakeUnsigned<absl::uint128> { 79 using type = absl::uint128; 80 }; 81 82 template <typename T> 83 struct IsUnsigned : std::is_unsigned<T> {}; 84 template <> 85 struct IsUnsigned<absl::int128> : std::false_type {}; 86 template <> 87 struct IsUnsigned<absl::uint128> : std::true_type {}; 88 89 // unsigned_bits<N>::type returns the unsigned int type with the indicated 90 // number of bits. 91 template <size_t N> 92 struct unsigned_bits; 93 94 template <> 95 struct unsigned_bits<8> { 96 using type = uint8_t; 97 }; 98 template <> 99 struct unsigned_bits<16> { 100 using type = uint16_t; 101 }; 102 template <> 103 struct unsigned_bits<32> { 104 using type = uint32_t; 105 }; 106 template <> 107 struct unsigned_bits<64> { 108 using type = uint64_t; 109 }; 110 111 template <> 112 struct unsigned_bits<128> { 113 using type = absl::uint128; 114 }; 115 116 // 256-bit wrapper for wide multiplications. 117 struct U256 { 118 uint128 hi; 119 uint128 lo; 120 }; 121 template <> 122 struct unsigned_bits<256> { 123 using type = U256; 124 }; 125 126 template <typename IntType> 127 struct make_unsigned_bits { 128 using type = typename unsigned_bits< 129 std::numeric_limits<typename MakeUnsigned<IntType>::type>::digits>::type; 130 }; 131 132 template <typename T> 133 int BitWidth(T v) { 134 // Workaround for bit_width not supporting int128. 135 // Don't hardcode `64` to make sure this code does not trigger compiler 136 // warnings in smaller types. 137 constexpr int half_bits = sizeof(T) * 8 / 2; 138 if (sizeof(T) == 16 && (v >> half_bits) != 0) { 139 return bit_width(static_cast<uint64_t>(v >> half_bits)) + half_bits; 140 } else { 141 return bit_width(static_cast<uint64_t>(v)); 142 } 143 } 144 145 } // namespace random_internal 146 ABSL_NAMESPACE_END 147 } // namespace absl 148 149 #endif // ABSL_RANDOM_INTERNAL_TRAITS_H_ 150