header_utils
Loading...
Searching...
No Matches
bits.h
1
4
5#pragma once
6
7#include <bit>
8#include <stdexcept>
9
10#include "cpp23.h"
11
12#if !defined(__cpp_concepts)
13#error "This library requires concepts"
14#endif
15
16namespace ghassanpl
17{
21
27 template<typename T>
28 concept bit_integral = std::is_integral_v<T> && !std::is_same_v<std::decay_t<T>, bool>;
29
32 template <typename T>
33 constexpr inline auto bit_count = sizeof(T) * CHAR_BIT;
34
36 constexpr inline uint64_t all_bits = ~uint64_t{ 0 };
37
39 template <size_t BEGIN, size_t END>
40 constexpr inline uint64_t bit_mask_v = (all_bits >> (64 - END)) << BEGIN;
41
43 template <bit_integral FOR>
44 constexpr inline uint64_t bit_mask_for_v = (all_bits >> (64 - bit_count<FOR>));
45
46 template <typename TO, typename FROM>
47 concept bit_castable = std::is_trivially_copyable_v<TO> && std::is_trivially_copyable_v<FROM> && sizeof(TO) == sizeof(FROM);
48
49 namespace detail
50 {
51 template <size_t N>
52 struct uintN_t_t;
53 template <> struct uintN_t_t<8> { using value = uint8_t; };
54 template <> struct uintN_t_t<16> { using value = uint16_t; };
55 template <> struct uintN_t_t<32> { using value = uint32_t; };
56 template <> struct uintN_t_t<64> { using value = uint64_t; };
57 template <size_t N>
58 requires (N < 8)
59 struct uintN_t_t<N>
60 {
61 using value = uint8_t;
62 };
63 }
64
66 template <size_t N>
67 using uintN_t = typename detail::uintN_t_t<N>::value;
68
69 namespace detail
70 {
71 template <size_t N>
72 struct intN_t_t
73 {
74 using value = std::make_signed_t<uintN_t<N>>;
75 };
76 }
77
79 template <size_t N>
80 using intN_t = typename detail::intN_t_t<N>::value;
81
82 namespace detail
83 {
84 template <bool SIGNED, size_t N>
85 struct sintN_t_t;
86 template <size_t N> struct sintN_t_t<false, N> { using value = uintN_t<N>; };
87 template <size_t N> struct sintN_t_t<true, N> { using value = intN_t<N>; };
88 }
89
91 template <bool SIGNED, size_t N>
92 using sintN_t = typename detail::sintN_t_t<SIGNED, N>::value;
93
95 template <bit_integral T>
96 constexpr auto most_significant_half(T v) noexcept
97 {
98 constexpr auto bit_count = ghassanpl::bit_count<T>;
99 constexpr auto bit_count_half = bit_count / 2;
101 }
102
104 template <bit_integral T>
105 constexpr auto least_significant_half(T v) noexcept
106 {
107 constexpr auto bit_count = ghassanpl::bit_count<T>;
108 constexpr auto bit_count_half = bit_count / 2;
110 }
111
114
116 template <bit_integral B>
117 constexpr B to_big_endian(B val) noexcept { if constexpr (std::endian::native == std::endian::big) return val; else return byteswap(val); }
118
120 template <bit_integral B>
121 constexpr B to_little_endian(B val) noexcept { if constexpr (std::endian::native == std::endian::little) return val; else return byteswap(val); }
122
124 template <std::endian ENDIANNESS, bit_integral B>
125 constexpr B to_endian(B val) noexcept { if constexpr (std::endian::native == ENDIANNESS) return val; else return byteswap(val); }
126
128 template <bit_integral B>
129 constexpr B to_endian(B val, std::endian endianness) noexcept { if (std::endian::native == endianness) return val; else return byteswap(val); }
130
132
134 constexpr inline size_t dynamic_bit_number = size_t(-1);
135
136 namespace detail
137 {
138 template <size_t NUM>
139 using bit_num_t = std::integral_constant<size_t, NUM>;
140
141 template <size_t NUM>
142 constexpr inline auto bit_num = bit_num_t<NUM>{};
143
144 template <bit_integral VALUE_TYPE, size_t BIT_NUM>
145 struct bit_num_base
146 {
147 using unsigned_value_type = std::make_unsigned_t<VALUE_TYPE>;
148 protected:
149 static constexpr VALUE_TYPE m_bit_mask = std::bit_cast<VALUE_TYPE>(unsigned_value_type(unsigned_value_type(1) << BIT_NUM % bit_count<VALUE_TYPE>));
150 };
151
152 template <bit_integral VALUE_TYPE>
153 struct bit_num_base<VALUE_TYPE, dynamic_bit_number>
154 {
155 using unsigned_value_type = std::make_unsigned_t<VALUE_TYPE>;
156 protected:
157 constexpr bit_num_base(size_t bitnum) noexcept : m_bit_mask(std::bit_cast<VALUE_TYPE>(unsigned_value_type(unsigned_value_type(1) << bitnum % bit_count<VALUE_TYPE>))) {}
158 VALUE_TYPE m_bit_mask;
159 };
160 }
161
163 template <bit_integral VALUE_TYPE, size_t BIT_NUM = dynamic_bit_number>
164 struct bit_reference : public detail::bit_num_base<VALUE_TYPE, BIT_NUM>
165 {
166 using base_type = detail::bit_num_base<VALUE_TYPE, BIT_NUM>;
167 static constexpr size_t value_bit_count = bit_count<VALUE_TYPE>;
168
169 static constexpr bool is_static = BIT_NUM != dynamic_bit_number;
170 static constexpr bool is_const = std::is_const_v<VALUE_TYPE>;
171
172 constexpr bit_reference(VALUE_TYPE& ref, size_t bitnum) requires (!is_static)
173 : base_type(bitnum)
174 , m_value_ref(ref)
175 {
176 if (bitnum >= value_bit_count)
177 throw std::invalid_argument("bit_num can't be greater than or equal to the number of bits in the value type");
178 }
179
180 constexpr bit_reference(VALUE_TYPE& ref, detail::bit_num_t<BIT_NUM> = {}) noexcept requires is_static
181 : m_value_ref(ref)
182 {
183 static_assert(BIT_NUM < value_bit_count, "BIT_NUM template argument can't be greater than or equal to the number of bits in the value type");
184 }
185
186 constexpr bit_reference& operator=(bool val) noexcept requires (!is_const)
187 {
188 if (val)
189 m_value_ref |= this->m_bit_mask;
190 else
191 m_value_ref &= ~this->m_bit_mask;
192 return *this;
193 }
194
195 [[nodiscard]] explicit constexpr operator bool() const noexcept
196 {
197 return (m_value_ref & this->m_bit_mask) != 0;
198 }
199
200 template <bit_integral OTHER_VALUE_TYPE, size_t OTHER_BIT_NUM>
201 [[nodiscard]] constexpr bool operator==(bit_reference<OTHER_VALUE_TYPE, OTHER_BIT_NUM> const& other) const noexcept
202 {
203 return this->operator bool() == other.operator bool();
204 }
205
206 template <bit_integral OTHER_VALUE_TYPE, size_t OTHER_BIT_NUM>
207 [[nodiscard]] constexpr auto operator<=>(bit_reference<OTHER_VALUE_TYPE, OTHER_BIT_NUM> const& other) const noexcept
208 {
209 return this->operator bool() <=> other.operator bool();
210 }
211
213 [[nodiscard]] constexpr auto& integer_value() const noexcept { return m_value_ref; }
214
216 [[nodiscard]] constexpr size_t bit_number() const noexcept
217 {
218 if constexpr (is_static)
219 return BIT_NUM;
220 else
221 return std::countr_zero(std::bit_cast<std::make_unsigned_t<VALUE_TYPE>>(this->m_bit_mask));
222 }
223
224 private:
225
226 VALUE_TYPE& m_value_ref;
227 };
228
230 template <bit_integral VALUE_TYPE>
231 bit_reference(VALUE_TYPE&, size_t) -> bit_reference<VALUE_TYPE>;
232 template <bit_integral VALUE_TYPE, size_t BIT_NUM>
233 bit_reference(VALUE_TYPE&, detail::bit_num_t<BIT_NUM>) -> bit_reference<VALUE_TYPE, BIT_NUM>;
235
237}
Whether or not a type is integral (but not a bool).
Definition bits.h:28
constexpr uint64_t all_bits
A value of type uint64_t with all bits set.
Definition bits.h:36
typename detail::sintN_t_t< SIGNED, N >::value sintN_t
A signed integer type for the given PoT bit size.
Definition bits.h:92
constexpr size_t dynamic_bit_number
Used to specify that a ghassanpl::bit_reference references a bit number given at runtime.
Definition bits.h:134
constexpr B to_big_endian(B val) noexcept
Returns val in its big-endian representation.
Definition bits.h:117
constexpr uint64_t bit_mask_for_v
Value with all bits available for the FOR type set (e.g. first 8 bits for uint8_t will be set,...
Definition bits.h:44
constexpr auto least_significant_half(T v) noexcept
Returns an integer with the N/2 least significant bits of the given N-bit integer.
Definition bits.h:105
constexpr B to_little_endian(B val) noexcept
Returns val in its big-endian representation.
Definition bits.h:121
typename detail::uintN_t_t< N >::value uintN_t
An unsigned integer type for the given PoT bit size.
Definition bits.h:67
constexpr B to_endian(B val) noexcept
Returns val in its ENDIANNESS representation.
Definition bits.h:125
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
constexpr auto most_significant_half(T v) noexcept
Returns an integer with the N/2 most significant bits of the given N-bit integer.
Definition bits.h:96
constexpr uint64_t bit_mask_v
Value with bits between BEGIN and END (exclusive) set.
Definition bits.h:40
typename detail::intN_t_t< N >::value intN_t
An integer type for the given PoT bit size.
Definition bits.h:80
The below code is based on Sun's libm library code, which is licensed under the following license:
Primary namespace for everything in this library.
Definition align+rec2.h:10
Models a reference to a specific bit in a variable. Can be a statically-defined bit number (BIT_NUM !...
Definition bits.h:165
constexpr size_t bit_number() const noexcept
Returns the bit number of the referenced bit.
Definition bits.h:216
constexpr auto & integer_value() const noexcept
Return the value of the referenced variable.
Definition bits.h:213