11 #include <type_traits>
12 #if !defined(__GNUC__) && (defined(_WIN32) || defined(_WIN64))
18 template<typename To
, typename From
>
19 std::enable_if_t
<sizeof(To
) == sizeof(From
) && std::is_trivially_copyable_v
<From
>
20 && std::is_trivially_copyable_v
<To
>,
21 To
> bit_cast(const From
&src
) noexcept
23 alignas(To
) std::array
<char,sizeof(To
)> dst
;
24 std::memcpy(dst
.data(), &src
, sizeof(To
));
25 return *std::launder(reinterpret_cast<To
*>(dst
.data()));
30 little
= __ORDER_LITTLE_ENDIAN__
,
31 big
= __ORDER_BIG_ENDIAN__
,
32 native
= __BYTE_ORDER__
37 /* This doesn't support mixed-endian. */
39 constexpr bool IsLittleEndian() noexcept
41 static_assert(sizeof(char) < sizeof(int), "char is too big");
43 constexpr int test_val
{1};
44 return static_cast<const char&>(test_val
) ? true : false;
46 } // namespace detail_
51 native
= detail_::IsLittleEndian() ? little
: big
56 /* Define popcount (population count/count 1 bits) and countr_zero (count
57 * trailing zero bits, starting from the lsb) methods, for various integer
63 inline int popcount(unsigned long long val
) noexcept
{ return __builtin_popcountll(val
); }
64 inline int popcount(unsigned long val
) noexcept
{ return __builtin_popcountl(val
); }
65 inline int popcount(unsigned int val
) noexcept
{ return __builtin_popcount(val
); }
67 inline int countr_zero(unsigned long long val
) noexcept
{ return __builtin_ctzll(val
); }
68 inline int countr_zero(unsigned long val
) noexcept
{ return __builtin_ctzl(val
); }
69 inline int countr_zero(unsigned int val
) noexcept
{ return __builtin_ctz(val
); }
70 } // namespace detail_
73 inline std::enable_if_t
<std::is_integral
<T
>::value
&& std::is_unsigned
<T
>::value
,
74 int> popcount(T v
) noexcept
{ return detail_::popcount(v
); }
77 inline std::enable_if_t
<std::is_integral
<T
>::value
&& std::is_unsigned
<T
>::value
,
78 int> countr_zero(T val
) noexcept
79 { return val
? detail_::countr_zero(val
) : std::numeric_limits
<T
>::digits
; }
83 /* There be black magics here. The popcount method is derived from
84 * https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
85 * while the ctz-utilizing-popcount algorithm is shown here
86 * http://www.hackersdelight.org/hdcodetxt/ntz.c.txt
87 * as the ntz2 variant. These likely aren't the most efficient methods, but
88 * they're good enough if the GCC built-ins aren't available.
91 template<typename T
, size_t = std::numeric_limits
<T
>::digits
>
92 struct fast_utype
{ };
94 struct fast_utype
<T
,8> { using type
= std::uint_fast8_t; };
96 struct fast_utype
<T
,16> { using type
= std::uint_fast16_t; };
98 struct fast_utype
<T
,32> { using type
= std::uint_fast32_t; };
100 struct fast_utype
<T
,64> { using type
= std::uint_fast64_t; };
103 constexpr T
repbits(unsigned char bits
) noexcept
106 for(size_t i
{1};i
< sizeof(T
);++i
)
107 ret
= (ret
<<8) | bits
;
110 } // namespace detail_
113 constexpr std::enable_if_t
<std::is_integral
<T
>::value
&& std::is_unsigned
<T
>::value
,
114 int> popcount(T val
) noexcept
116 using fast_type
= typename
detail_::fast_utype
<T
>::type
;
117 constexpr fast_type b01010101
{detail_::repbits
<fast_type
>(0x55)};
118 constexpr fast_type b00110011
{detail_::repbits
<fast_type
>(0x33)};
119 constexpr fast_type b00001111
{detail_::repbits
<fast_type
>(0x0f)};
120 constexpr fast_type b00000001
{detail_::repbits
<fast_type
>(0x01)};
122 fast_type v
{fast_type
{val
} - ((fast_type
{val
} >> 1) & b01010101
)};
123 v
= (v
& b00110011
) + ((v
>> 2) & b00110011
);
124 v
= (v
+ (v
>> 4)) & b00001111
;
125 return static_cast<int>(((v
* b00000001
) >> ((sizeof(T
)-1)*8)) & 0xff);
131 inline std::enable_if_t
<std::is_integral
<T
>::value
&& std::is_unsigned
<T
>::value
132 && std::numeric_limits
<T
>::digits
<= 32,
133 int> countr_zero(T v
)
135 unsigned long idx
{std::numeric_limits
<T
>::digits
};
136 _BitScanForward(&idx
, static_cast<uint32_t>(v
));
137 return static_cast<int>(idx
);
141 inline std::enable_if_t
<std::is_integral
<T
>::value
&& std::is_unsigned
<T
>::value
142 && 32 < std::numeric_limits
<T
>::digits
&& std::numeric_limits
<T
>::digits
<= 64,
143 int> countr_zero(T v
)
145 unsigned long idx
{std::numeric_limits
<T
>::digits
};
147 _BitScanForward64(&idx
, v
);
149 if(!_BitScanForward(&idx
, static_cast<uint32_t>(v
)))
151 if(_BitScanForward(&idx
, static_cast<uint32_t>(v
>>32)))
155 return static_cast<int>(idx
);
161 constexpr std::enable_if_t
<std::is_integral
<T
>::value
&& std::is_unsigned
<T
>::value
,
162 int> countr_zero(T value
)
163 { return popcount(static_cast<T
>(~value
& (value
- 1))); }
170 #endif /* AL_BIT_H */