Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions docs/bit.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,37 @@ constexpr std::size_t x = stdx::bit_size<std::uint8_t>();
static_assert(x == 8);
----

=== `bit_structure`

`bit_structure` is the opposite of
xref:bit.adoc#_bit_destructure[`bit_destructure`]: a function for packing
several unsigned integral values into a larger bit width value. It is a more
general case of xref:bit.adoc#_bit_pack[`bit_pack`].

[source,cpp]
----
std::uint32_t const x = 0x1234'5678u;
auto const [a, b, c] = stdx::bit_destructure<8, 24>(x);
// a = 0x78u, b = 0x3456u, c = 0x12u
// a, b and c are all std::uint32_t

auto const x = stdx::bit_structure<8, 24>(a, b, c);
// x = 0x1234'5678u (a std::uint32_t)

// or:
auto const y = stdx::bit_structure<std::uint64_t, 8, 24>(a, b, c);
// y = 0x1234'5678u (a std::uint64_t)
----

The arguments to `bit_structure` must all be unsigned integral types. If the
type template argument is omitted as in the first example here, the
https://cppreference.com/cpp/types/common_type[`std::common_type_t`] of the
given arguments will be assumed.

NOTE: Unlike `bit_pack`, `bit_structure` takes the arguments in
_increasing_ order of significance, and the template arguments representing the
split boundaries must be in increasing order.
Comment thread
elbeno marked this conversation as resolved.

=== `bit_unpack`

`bit_unpack` is a function for unpacking an unsigned integral values into multiple
Expand Down
18 changes: 18 additions & 0 deletions include/stdx/bit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,5 +462,23 @@ constexpr auto bit_destructure(T t) -> std::array<T, sizeof...(Offsets) + 1> {
return bit_detail::bit_destructure_impl<Offsets..., bit_size<T>()>(
t, std::make_index_sequence<sizeof...(Offsets) + 1>{});
}

template <unsigned_integral T, std::size_t... Offsets, unsigned_integral... Ts>
requires(sizeof...(Ts) - sizeof...(Offsets) == 1)
constexpr auto bit_structure(Ts... ts) -> T {
constexpr auto shifted = []<std::size_t Offset>(auto x) -> T {
return static_cast<T>(static_cast<T>(x) << Offset);
};
return [&]<std::size_t... Os>() -> T {
return (T{} | ... | shifted.template operator()<Os>(ts));
}.template operator()<std::size_t{}, Offsets...>();
}

template <std::size_t... Offsets, unsigned_integral... Ts>
requires(sizeof...(Ts) - sizeof...(Offsets) == 1)
constexpr auto bit_structure(Ts... ts) -> std::common_type_t<Ts...> {
using T = std::common_type_t<Ts...>;
return bit_structure<T, Offsets...>(ts...);
}
} // namespace v1
} // namespace stdx
36 changes: 36 additions & 0 deletions test/bit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,3 +459,39 @@ TEST_CASE("bit_destructure (split in three)", "[bit]") {
CHECK(b == 0x3456u);
CHECK(c == 0x12u);
}

TEST_CASE("bit_structure (degenerate case)", "[bit]") {
constexpr auto x = stdx::bit_structure<std::uint16_t>(0b11u);
STATIC_CHECK(x == 0b11u);
STATIC_CHECK(std::same_as<decltype(x), std::uint16_t const>);
}

TEST_CASE("bit_structure (two parts)", "[bit]") {
constexpr auto x = stdx::bit_structure<std::uint16_t, 2>(0b01u, 0b10u);
STATIC_CHECK(x == 0b10'01u);
STATIC_CHECK(std::same_as<decltype(x), std::uint16_t const>);
}

TEST_CASE("bit_structure (three parts)", "[bit]") {
constexpr auto x =
stdx::bit_structure<std::uint32_t, 3, 5>(0b01u, 0b10u, 0b10u);
STATIC_CHECK(x == 0b10'10'001u);
STATIC_CHECK(std::same_as<decltype(x), std::uint32_t const>);
}

TEST_CASE("bit_{de}structure round-trip", "[bit]") {
constexpr auto x = std::uint32_t{0x1234'5678u};
auto [a, b, c] = stdx::bit_destructure<8, 24>(x);
auto y = stdx::bit_structure<std::uint32_t, 8, 24>(a, b, c);
CHECK(x == y);
}

TEST_CASE("bit_structure (inferred type)", "[bit]") {
constexpr auto x = std::uint32_t{0x1234'5678u};
auto [a, b, c] = stdx::bit_destructure<8, 24>(x);
STATIC_CHECK(std::same_as<decltype(a), std::uint32_t>);
STATIC_CHECK(std::same_as<decltype(b), std::uint32_t>);
STATIC_CHECK(std::same_as<decltype(c), std::uint32_t>);
auto y = stdx::bit_structure<8, 24>(a, b, c);
CHECK(x == y);
}