12#if !defined(__cpp_concepts)
13#error "This library requires concepts"
28 concept bit_integral = std::is_integral_v<T> && !std::is_same_v<std::decay_t<T>,
bool>;
33 constexpr inline auto bit_count =
sizeof(T) * CHAR_BIT;
36 constexpr inline uint64_t
all_bits = ~uint64_t{ 0 };
39 template <
size_t BEGIN,
size_t END>
43 template <bit_
integral FOR>
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);
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; };
67 using uintN_t =
typename detail::uintN_t_t<N>::value;
74 using value = std::make_signed_t<uintN_t<N>>;
80 using intN_t =
typename detail::intN_t_t<N>::value;
84 template <
bool SIGNED,
size_t N>
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>; };
91 template <
bool SIGNED,
size_t N>
92 using sintN_t =
typename detail::sintN_t_t<SIGNED, N>::value;
95 template <bit_
integral T>
104 template <bit_
integral T>
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); }
120 template <bit_
integral B>
124 template <std::endian ENDIANNESS, bit_
integral B>
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); }
138 template <
size_t NUM>
139 using bit_num_t = std::integral_constant<size_t, NUM>;
141 template <
size_t NUM>
144 template <bit_
integral VALUE_TYPE,
size_t BIT_NUM>
147 using unsigned_value_type = std::make_unsigned_t<VALUE_TYPE>;
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>));
152 template <bit_
integral VALUE_TYPE>
155 using unsigned_value_type = std::make_unsigned_t<VALUE_TYPE>;
158 VALUE_TYPE m_bit_mask;
163 template <bit_
integral VALUE_TYPE,
size_t BIT_NUM = dynamic_bit_number>
166 using base_type = detail::bit_num_base<VALUE_TYPE, BIT_NUM>;
170 static constexpr bool is_const = std::is_const_v<VALUE_TYPE>;
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");
180 constexpr bit_reference(VALUE_TYPE& ref, detail::bit_num_t<BIT_NUM> = {})
noexcept requires is_static
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");
189 m_value_ref |= this->m_bit_mask;
191 m_value_ref &=
~this->m_bit_mask;
195 [[
nodiscard]]
explicit constexpr operator bool()
const noexcept
197 return (m_value_ref & this->m_bit_mask) != 0;
200 template <bit_
integral OTHER_VALUE_TYPE,
size_t OTHER_BIT_NUM>
203 return this->
operator bool() == other.operator
bool();
206 template <bit_
integral OTHER_VALUE_TYPE,
size_t OTHER_BIT_NUM>
209 return this->
operator bool() <=> other.operator
bool();
218 if constexpr (is_static)
221 return std::countr_zero(std::bit_cast<std::make_unsigned_t<VALUE_TYPE>>(this->m_bit_mask));
226 VALUE_TYPE& m_value_ref;
230 template <bit_
integral VALUE_TYPE>
232 template <bit_
integral VALUE_TYPE,
size_t BIT_NUM>
Whether or not a type is integral (but not a bool).
constexpr uint64_t all_bits
A value of type uint64_t with all bits set.
typename detail::sintN_t_t< SIGNED, N >::value sintN_t
A signed integer type for the given PoT bit size.
constexpr size_t dynamic_bit_number
Used to specify that a ghassanpl::bit_reference references a bit number given at runtime.
constexpr B to_big_endian(B val) noexcept
Returns val in its big-endian representation.
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,...
constexpr auto least_significant_half(T v) noexcept
Returns an integer with the N/2 least significant bits of the given N-bit integer.
constexpr B to_little_endian(B val) noexcept
Returns val in its big-endian representation.
typename detail::uintN_t_t< N >::value uintN_t
An unsigned integer type for the given PoT bit size.
constexpr B to_endian(B val) noexcept
Returns val in its ENDIANNESS representation.
constexpr auto bit_count
Equal to the number of bits in the type.
constexpr auto most_significant_half(T v) noexcept
Returns an integer with the N/2 most significant bits of the given N-bit integer.
constexpr uint64_t bit_mask_v
Value with bits between BEGIN and END (exclusive) set.
typename detail::intN_t_t< N >::value intN_t
An integer type for the given PoT bit size.
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.
Models a reference to a specific bit in a variable. Can be a statically-defined bit number (BIT_NUM !...
constexpr size_t bit_number() const noexcept
Returns the bit number of the referenced bit.
constexpr auto & integer_value() const noexcept
Return the value of the referenced variable.