24#ifndef UGMISC_BITOPS_HPP
25#define UGMISC_BITOPS_HPP
48#ifdef UGMISC_HAVE_BITOPS
108enum BitFunc { CLZ, CR1, CL1, CRZ };
118template<BitFunc F, class T, int Bits = std::numeric_limits<T>::digits,
int Shift = 0 >
119static constexpr auto cxx(T v)
noexcept
122 constexpr int max_bits = std::numeric_limits<T>::digits;
123 constexpr T all_ones = ~((T)0);
124 constexpr T mask_rightshifted = (all_ones >> (max_bits - Bits));
126 static_assert( Bits >= 1 );
127 static_assert( Bits + Shift <= max_bits );
129 constexpr bool from_left = F == CLZ || F == CL1;
130 constexpr bool count_ones = F == CL1 || F == CR1;
131 constexpr bool count_zeros = ! count_ones;
132 constexpr T mask = mask_rightshifted << Shift;
134 bool all_set = (mask & v) == mask;
135 bool all_clear = (mask & v) == 0;
136 bool all_bits_of_counted_state = (count_ones && all_set) || (count_zeros && all_clear);
137 bool all_bits_of_uncounted_state = (count_ones && all_clear) || (count_ones && all_set);
138 bool trivial_result = all_bits_of_counted_state || all_bits_of_uncounted_state;
151 if constexpr ( Bits == 1 ) {
152 return all_bits_of_counted_state ? 1 : 0;
154 if ( trivial_result ) {
155 return all_bits_of_counted_state ? Bits : 0;
158 constexpr int left_partition_bits = Bits/2;
159 constexpr int right_partition_bits = Bits - left_partition_bits;
160 constexpr int left_partition_shift = Shift + right_partition_bits;
161 constexpr int right_partition_shift = Shift;
163 constexpr int first_partition_bits
164 = from_left ? left_partition_bits : right_partition_bits;
165 constexpr int second_partition_bits
166 = from_left ? right_partition_bits : left_partition_bits;
168 constexpr int first_partition_shift
169 = from_left ? left_partition_shift : right_partition_shift;
170 constexpr int second_partition_shift
171 = from_left ? right_partition_shift : left_partition_shift;
173 int first_result = cxx<F, T, first_partition_bits, first_partition_shift>(v);
175 if ( first_result < first_partition_bits ) {
178 int second_result = cxx<F, T, second_partition_bits, second_partition_shift>(v);
179 return first_result + second_result;
188template<
class T,
class=
int>
constexpr bool is_std_clz_type =
false;
189template<
class T,
class=
int>
constexpr bool is_std_crz_type =
false;
190template<
class T,
class=
int>
constexpr bool is_std_cl1_type =
false;
191template<
class T,
class=
int>
constexpr bool is_std_cr1_type =
false;
192template<
class T,
class=
int>
constexpr bool is_std_bitwidth_type =
false;
193#ifdef UGMISC_HAVE_BITOPS
196is_std_clz_type<T, decltype(::std::countl_zero(std::declval<T>()))>
201is_std_crz_type<T, decltype(::std::countr_zero(std::declval<T>()))>
206is_std_cl1_type<T, decltype(::std::countl_one(std::declval<T>()))>
211is_std_cr1_type<T, decltype(::std::countr_one(std::declval<T>()))>
216is_std_bitwidth_type<T, decltype(::std::bit_width(std::declval<T>()))>
229template<
class T,
bool=true>
231 constexpr int operator()(T x)
const noexcept {
232 return cxx<_bitops::CLZ, T>(x);
236template<
class T,
bool=true>
238 constexpr int operator()(T x)
const noexcept {
239 return cxx<_bitops::CL1, T>(x);
243template<
class T,
bool=true>
245 constexpr int operator()(T x)
const noexcept {
246 return cxx<_bitops::CRZ, T>(x);
250template<
class T,
bool=true>
252 constexpr int operator()(T x)
const noexcept {
253 return cxx<_bitops::CR1, T>(x);
257template<
class T,
bool=true>
258struct call_bitwidth {
259 constexpr int operator()(T x)
const noexcept {
260 return std::numeric_limits<T>::digits -
clz(x);
264#ifdef UGMISC_HAVE_BITOPS
266struct call_clz<T, is_std_clz_type<T>> {
267 constexpr int operator()(T x)
const noexcept {
268 return ::std::countl_zero(x);
273struct call_cl1<T, is_std_clz_type<T>> {
274 constexpr int operator()(T x)
const noexcept {
275 return ::std::countl_one(x);
280struct call_crz<T, is_std_clz_type<T>> {
281 constexpr int operator()(T x)
const noexcept {
282 return ::std::countr_zero(x);
287struct call_cr1<T, is_std_clz_type<T>> {
288 constexpr int operator()(T x)
const noexcept {
289 return ::std::countr_one(x);
294struct call_bitwidth<T, is_std_clz_type<T>> {
295 constexpr int operator()(T x)
const noexcept {
296 return ::std::bit_width(x);
311 return _bitops::call_clz<T>{}(x);
316 return _bitops::call_cl1<T>{}(x);
321 return _bitops::call_crz<T>{}(x);
326 return _bitops::call_cr1<T>{}(x);
331 return _bitops::call_bitwidth<T>{}(x);
constexpr auto clz(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:310
constexpr auto crz(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:320
constexpr auto bitwidth(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:330
constexpr auto cl1(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:315
constexpr auto cr1(T) noexcept -> UGMISC_BITWISE_UINT_RETURN(T, int)
Definition bitops.hpp:325
Utility required by other ugmisc headers.
#define UGMISC_BITWISE_UINT_RETURN(T, R)
Definition sfinae_helpers.hpp:224