cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
bit.hpp
1#pragma once
2
3#include <limits>
4#include <type_traits>
5
6#pragma GCC push_options
7#ifndef _CPLIB_NO_FORCE_BMI2_
8#pragma GCC target("abm,bmi,bmi2")
9#endif
10
11// Backport some functions in <bit> in C++20.
12
13namespace cplib::port {
14
15namespace impl {
16
17template <typename T>
18constexpr bool is_unsigned_integer_v = std::is_unsigned_v<T> && !std::is_same_v<T, bool>;
19
20template <typename T>
21constexpr bool long_long_or_smaller = std::numeric_limits<T>::digits <= std::numeric_limits<unsigned long long>::digits;
22
23template <typename T>
24constexpr bool int_or_smaller = std::numeric_limits<T>::digits <= std::numeric_limits<unsigned int>::digits;
25
26} // namespace impl
27
28template <typename T, std::enable_if_t<impl::is_unsigned_integer_v<T>>* = nullptr>
29constexpr int countl_zero(T x) noexcept {
30 static_assert(impl::long_long_or_smaller<T>);
31 if (x == 0) {
32 return std::numeric_limits<T>::digits;
33 } else if (impl::int_or_smaller<T>) {
34 return __builtin_clz(x) - std::numeric_limits<unsigned int>::digits + std::numeric_limits<T>::digits;
35 } else {
36 return __builtin_clzll(x) - std::numeric_limits<unsigned long long>::digits + std::numeric_limits<T>::digits;
37 }
38};
39
40template <typename T, std::enable_if_t<impl::is_unsigned_integer_v<T>>* = nullptr>
41constexpr int countr_zero(T x) noexcept {
42 static_assert(impl::long_long_or_smaller<T>);
43 if (x == 0) {
44 return std::numeric_limits<T>::digits;
45 } else if (impl::int_or_smaller<T>) {
46 return __builtin_ctz(x);
47 } else {
48 return __builtin_ctzll(x);
49 }
50};
51
52template <typename T, std::enable_if_t<impl::is_unsigned_integer_v<T>>* = nullptr>
53constexpr int bit_width(T x) noexcept {
54 return std::numeric_limits<T>::digits - countl_zero(x);
55};
56
57template <typename T, std::enable_if_t<impl::is_unsigned_integer_v<T>>* = nullptr>
58constexpr T bit_floor(T x) noexcept {
59 return x == 0 ? 0 : T(1) << (bit_width(x) - 1);
60};
61
62template <typename T, std::enable_if_t<impl::is_unsigned_integer_v<T>>* = nullptr>
63constexpr T bit_ceil(T x) noexcept {
64 return x <= T(1) ? T(1) : T(1) << bit_width(x - 1);
65};
66
67template <typename T, std::enable_if_t<impl::is_unsigned_integer_v<T>>* = nullptr>
68constexpr bool has_single_bit(T x) noexcept {
69 return x != 0 && (x & (x - 1)) == 0;
70};
71
72template <typename T, std::enable_if_t<impl::is_unsigned_integer_v<T>>* = nullptr>
73constexpr int popcount(T x) noexcept {
74 static_assert(impl::long_long_or_smaller<T>);
75 if (impl::int_or_smaller<T>) {
76 return __builtin_popcount(x);
77 } else {
78 return __builtin_popcountll(x);
79 }
80};
81
82} // namespace cplib::port
83
84#pragma GCC pop_options