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