xref: /aosp_15_r20/external/cronet/third_party/abseil-cpp/absl/random/internal/traits.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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