5#ifndef UGMISC_BITOPS_HPP
6#define UGMISC_BITOPS_HPP
35#ifdef UGMISC_HAVE_BITOPS
95enum BitFunc { CLZ, CR1, CL1, CRZ };
105template<BitFunc F, class T, int Bits = std::numeric_limits<T>::digits,
int Shift = 0 >
106static constexpr auto cxx(T v)
noexcept
109 constexpr int max_bits = std::numeric_limits<T>::digits;
110 constexpr T all_ones = ~((T)0);
111 constexpr T mask_rightshifted = (all_ones >> (max_bits - Bits));
113 static_assert( Bits >= 1 );
114 static_assert( Bits + Shift <= max_bits );
116 constexpr bool from_left = F == CLZ || F == CL1;
117 constexpr bool count_ones = F == CL1 || F == CR1;
118 constexpr bool count_zeros = ! count_ones;
119 constexpr T mask = mask_rightshifted << Shift;
121 bool all_set = (mask & v) == mask;
122 bool all_clear = (mask & v) == 0;
123 bool all_bits_of_counted_state = (count_ones && all_set) || (count_zeros && all_clear);
124 bool all_bits_of_uncounted_state = (count_ones && all_clear) || (count_ones && all_set);
125 bool trivial_result = all_bits_of_counted_state || all_bits_of_uncounted_state;
138 if constexpr ( Bits == 1 ) {
139 return all_bits_of_counted_state ? 1 : 0;
141 if ( trivial_result ) {
142 return all_bits_of_counted_state ? Bits : 0;
145 constexpr int left_partition_bits = Bits/2;
146 constexpr int right_partition_bits = Bits - left_partition_bits;
147 constexpr int left_partition_shift = Shift + right_partition_bits;
148 constexpr int right_partition_shift = Shift;
150 constexpr int first_partition_bits
151 = from_left ? left_partition_bits : right_partition_bits;
152 constexpr int second_partition_bits
153 = from_left ? right_partition_bits : left_partition_bits;
155 constexpr int first_partition_shift
156 = from_left ? left_partition_shift : right_partition_shift;
157 constexpr int second_partition_shift
158 = from_left ? right_partition_shift : left_partition_shift;
160 int first_result = cxx<F, T, first_partition_bits, first_partition_shift>(v);
162 if ( first_result < first_partition_bits ) {
165 int second_result = cxx<F, T, second_partition_bits, second_partition_shift>(v);
166 return first_result + second_result;
175template<
class T,
class=
int>
constexpr bool is_std_clz_type =
false;
176template<
class T,
class=
int>
constexpr bool is_std_crz_type =
false;
177template<
class T,
class=
int>
constexpr bool is_std_cl1_type =
false;
178template<
class T,
class=
int>
constexpr bool is_std_cr1_type =
false;
179template<
class T,
class=
int>
constexpr bool is_std_bitwidth_type =
false;
180#ifdef UGMISC_HAVE_BITOPS
183is_std_clz_type<T, decltype(::std::countl_zero(std::declval<T>()))>
188is_std_crz_type<T, decltype(::std::countr_zero(std::declval<T>()))>
193is_std_cl1_type<T, decltype(::std::countl_one(std::declval<T>()))>
198is_std_cr1_type<T, decltype(::std::countr_one(std::declval<T>()))>
203is_std_bitwidth_type<T, decltype(::std::bit_width(std::declval<T>()))>
216template<
class T,
bool=true>
218 constexpr int operator()(T x)
const noexcept {
219 return cxx<_bitops::CLZ, T>(x);
223template<
class T,
bool=true>
225 constexpr int operator()(T x)
const noexcept {
226 return cxx<_bitops::CL1, T>(x);
230template<
class T,
bool=true>
232 constexpr int operator()(T x)
const noexcept {
233 return cxx<_bitops::CRZ, T>(x);
237template<
class T,
bool=true>
239 constexpr int operator()(T x)
const noexcept {
240 return cxx<_bitops::CR1, T>(x);
244template<
class T,
bool=true>
245struct call_bitwidth {
246 constexpr int operator()(T x)
const noexcept {
247 return std::numeric_limits<T>::digits -
clz(x);
251#ifdef UGMISC_HAVE_BITOPS
253struct call_clz<T, is_std_clz_type<T>> {
254 constexpr int operator()(T x)
const noexcept {
255 return ::std::countl_zero(x);
260struct call_cl1<T, is_std_clz_type<T>> {
261 constexpr int operator()(T x)
const noexcept {
262 return ::std::countl_one(x);
267struct call_crz<T, is_std_clz_type<T>> {
268 constexpr int operator()(T x)
const noexcept {
269 return ::std::countr_zero(x);
274struct call_cr1<T, is_std_clz_type<T>> {
275 constexpr int operator()(T x)
const noexcept {
276 return ::std::countr_one(x);
281struct call_bitwidth<T, is_std_clz_type<T>> {
282 constexpr int operator()(T x)
const noexcept {
283 return ::std::bit_width(x);
298 return _bitops::call_clz<T>{}(x);
303 return _bitops::call_cl1<T>{}(x);
308 return _bitops::call_crz<T>{}(x);
313 return _bitops::call_cr1<T>{}(x);
318 return _bitops::call_bitwidth<T>{}(x);
constexpr auto clz(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:297
constexpr auto crz(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:307
constexpr auto bitwidth(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:317
constexpr auto cl1(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:302
constexpr auto cr1(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:312
Utility required by other ugmisc headers.
#define UGMISC_BITWISE_UINT_RETURN(T, R)
Definition sfinae_helpers.hpp:201