<bit> Support
Description
The library provides thin wrappers around the C++20 <bit> functions for safe integer types.
Each function extracts the underlying value, delegates to the corresponding std:: function, and wraps the result back into the safe type where appropriate.
For u128, the functions delegate to the boost::int128 implementations.
#include <boost/safe_numbers/bit.hpp>
Power-of-Two Functions
has_single_bit
template <unsigned_library_type UnsignedInt>
constexpr auto has_single_bit(UnsignedInt x) noexcept -> bool;
Returns true if x is a power of two.
See std::has_single_bit.
bit_ceil
template <unsigned_library_type UnsignedInt>
constexpr auto bit_ceil(UnsignedInt x) noexcept -> UnsignedInt;
Returns the smallest power of two not less than x.
Undefined behavior if the result is not representable in the underlying type.
See std::bit_ceil.
bit_floor
template <unsigned_library_type UnsignedInt>
constexpr auto bit_floor(UnsignedInt x) noexcept -> UnsignedInt;
Returns the largest power of two not greater than x.
Returns zero if x is zero.
See std::bit_floor.
bit_width
template <unsigned_library_type UnsignedInt>
constexpr auto bit_width(UnsignedInt x) noexcept -> int;
Returns the number of bits needed to represent x (i.e., 1 + floor(log2(x)) for x > 0, or 0 for x == 0).
See std::bit_width.
Rotation Functions
rotl
template <unsigned_library_type UnsignedInt>
constexpr auto rotl(UnsignedInt x, int s) noexcept -> UnsignedInt;
Computes the result of bitwise left-rotating x by s positions.
See std::rotl.
rotr
template <unsigned_library_type UnsignedInt>
constexpr auto rotr(UnsignedInt x, int s) noexcept -> UnsignedInt;
Computes the result of bitwise right-rotating x by s positions.
See std::rotr.
Counting Functions
countl_zero
template <unsigned_library_type UnsignedInt>
constexpr auto countl_zero(UnsignedInt x) noexcept -> int;
Returns the number of consecutive 0-bits starting from the most significant bit.
See std::countl_zero.
countl_one
template <unsigned_library_type UnsignedInt>
constexpr auto countl_one(UnsignedInt x) noexcept -> int;
Returns the number of consecutive 1-bits starting from the most significant bit.
See std::countl_one.
countr_zero
template <unsigned_library_type UnsignedInt>
constexpr auto countr_zero(UnsignedInt x) noexcept -> int;
Returns the number of consecutive 0-bits starting from the least significant bit.
See std::countr_zero.
countr_one
template <unsigned_library_type UnsignedInt>
constexpr auto countr_one(UnsignedInt x) noexcept -> int;
Returns the number of consecutive 1-bits starting from the least significant bit.
See std::countr_one.
popcount
template <unsigned_library_type UnsignedInt>
constexpr auto popcount(UnsignedInt x) noexcept -> int;
Returns the number of 1-bits in x.
See std::popcount.
Byte Manipulation
byteswap
template <unsigned_library_type UnsignedInt>
constexpr auto byteswap(UnsignedInt x) noexcept -> UnsignedInt;
Reverses the bytes of x.
For standard unsigned types this delegates to std::byteswap (C++23).
For u128 this delegates to the boost::int128::byteswap implementation.
See std::byteswap.
Examples
// Copyright 2026 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/safe_numbers/unsigned_integers.hpp>
#include <boost/safe_numbers/bit.hpp>
#include <iostream>
int main()
{
using namespace boost::safe_numbers;
const u32 x {0b0000'0000'0000'0000'0000'0000'0010'1000}; // 40
// Power-of-two queries
std::cout << "has_single_bit(40) = " << has_single_bit(x) << '\n';
std::cout << "has_single_bit(32) = " << has_single_bit(u32{32}) << '\n';
std::cout << "bit_ceil(40) = " << static_cast<std::uint32_t>(bit_ceil(x)) << '\n';
std::cout << "bit_floor(40) = " << static_cast<std::uint32_t>(bit_floor(x)) << '\n';
std::cout << "bit_width(40) = " << bit_width(x) << '\n';
std::cout << '\n';
// Rotation
const u8 y {0b1011'0001}; // 177
std::cout << "rotl(0b10110001, 2) = " << static_cast<unsigned>(rotl(y, 2)) << '\n';
std::cout << "rotr(0b10110001, 2) = " << static_cast<unsigned>(rotr(y, 2)) << '\n';
std::cout << '\n';
// Counting
const u16 z {0b0000'1111'0000'0000}; // 3840
std::cout << "countl_zero(0x0F00) = " << countl_zero(z) << '\n';
std::cout << "countl_one(0x0F00) = " << countl_one(z) << '\n';
std::cout << "countr_zero(0x0F00) = " << countr_zero(z) << '\n';
std::cout << "countr_one(0x0F00) = " << countr_one(z) << '\n';
std::cout << "popcount(0x0F00) = " << popcount(z) << '\n';
std::cout << '\n';
// Byteswap
const u32 w {0x12345678};
std::cout << std::hex;
std::cout << "byteswap(0x12345678) = 0x" << static_cast<std::uint32_t>(byteswap(w)) << '\n';
return 0;
}
Output:
has_single_bit(40) = 0 has_single_bit(32) = 1 bit_ceil(40) = 64 bit_floor(40) = 32 bit_width(40) = 6 rotl(0b10110001, 2) = 198 rotr(0b10110001, 2) = 108 countl_zero(0x0F00) = 4 countl_one(0x0F00) = 0 countr_zero(0x0F00) = 8 countr_one(0x0F00) = 0 popcount(0x0F00) = 4 byteswap(0x12345678) = 0x78563412