Skip to content

Commit 67cde77

Browse files
committed
✨ Add bit_unpack
1 parent 57c87c2 commit 67cde77

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed

docs/bit.adoc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,37 @@ constexpr std::size_t x = stdx::bit_size<std::uint8_t>();
7979
static_assert(x == 8);
8080
----
8181

82+
=== `bit_unpack`
83+
84+
`bit_unpack` is a function for unpacking an unsigned integral values into multiple
85+
smaller bit width values.
86+
87+
[source,cpp]
88+
----
89+
auto const [a, b] = stdx::bit_unpack<std::uint16_t>(0x1234'5678u);
90+
assert(a == 0x1234u);
91+
assert(b == 0x5678u);
92+
----
93+
94+
`bit_unpack` can be used:
95+
96+
- to unpack a `std::uint16_t` into 2 `std::uint8_t`​s
97+
- to unpack a `std::uint32_t` into 2 `std::uint16_t`​s
98+
- to unpack a `std::uint32_t` into 4 `std::uint8_t`​s
99+
- to unpack a `std::uint64_t` into 2 `std::uint32_t`​s
100+
- to unpack a `std::uint64_t` into 4 `std::uint16_t`​s
101+
- to unpack a `std::uint64_t` into 8 `std::uint8_t`​s
102+
103+
The return value of `bit_unpack` is actually a `std::array` with elements in
104+
order of significance. In this way `bit_unpack` followed by `bit_pack` produces
105+
the original value.
106+
107+
[source,cpp]
108+
----
109+
constexpr auto a = stdx::bit_unpack<std::uint16_t>(0x1234'5678u);
110+
static_assert(stdx::bit_pack<std::uint32_t>(a[0], a[1]) == 0x1234'5678u);
111+
----
112+
82113
=== `smallest_uint`
83114

84115
`smallest_uint` is a function template that selects the smallest unsigned

include/stdx/bit.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <stdx/type_traits.hpp>
55
#include <stdx/utility.hpp>
66

7+
#include <array>
78
#include <climits>
89
#include <cstdint>
910
#include <limits>
@@ -306,6 +307,20 @@ constexpr inline auto bit_pack<std::uint64_t> =
306307
(static_cast<std::uint64_t>(b6) << 8u) | b7;
307308
}};
308309

310+
template <typename To, typename From> constexpr auto bit_unpack(From arg) {
311+
static_assert(unsigned_integral<To> and unsigned_integral<From>,
312+
"bit_unpack is undefined for those types");
313+
314+
constexpr auto sz = sized<From>{1}.template in<To>();
315+
auto r = bit_cast<std::array<To, sz>>(to_be(arg));
316+
if constexpr (stdx::endian::native == stdx::endian::little) {
317+
for (auto &elem : r) {
318+
elem = byteswap(elem);
319+
}
320+
}
321+
return r;
322+
}
323+
309324
namespace detail {
310325
template <typename T, std::size_t Bit>
311326
constexpr auto

test/bit.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,92 @@ TEMPLATE_TEST_CASE("bit_size", "[bit]", std::uint8_t, std::uint16_t,
249249
static_assert(stdx::bit_size<TestType>() ==
250250
std::numeric_limits<std::make_unsigned_t<TestType>>::digits);
251251
}
252+
253+
TEST_CASE("bit_unpack 64 -> 2x32", "[bit]") {
254+
auto const [a, b] =
255+
stdx::bit_unpack<std::uint32_t>(std::uint64_t{0x1234'5678'9abc'def0});
256+
CHECK(a == 0x1234'5678);
257+
CHECK(b == 0x9abc'def0);
258+
}
259+
260+
TEST_CASE("bit_unpack 32 -> 2x16", "[bit]") {
261+
auto const [a, b] =
262+
stdx::bit_unpack<std::uint16_t>(std::uint32_t{0x1234'5678});
263+
CHECK(a == 0x1234);
264+
CHECK(b == 0x5678);
265+
}
266+
267+
TEST_CASE("bit_unpack 64 -> 4x16", "[bit]") {
268+
auto const [a, b, c, d] =
269+
stdx::bit_unpack<std::uint16_t>(std::uint64_t{0x1234'5678'9abc'def0});
270+
CHECK(a == 0x1234);
271+
CHECK(b == 0x5678);
272+
CHECK(c == 0x9abc);
273+
CHECK(d == 0xdef0);
274+
}
275+
276+
TEST_CASE("bit_unpack 16 -> 2x8", "[bit]") {
277+
auto const [a, b] = stdx::bit_unpack<std::uint8_t>(std::uint16_t{0x1234});
278+
CHECK(a == 0x12);
279+
CHECK(b == 0x34);
280+
}
281+
282+
TEST_CASE("bit_unpack 32 -> 4x8", "[bit]") {
283+
auto const [a, b, c, d] =
284+
stdx::bit_unpack<std::uint8_t>(std::uint32_t{0x1234'5678});
285+
CHECK(a == 0x12);
286+
CHECK(b == 0x34);
287+
CHECK(c == 0x56);
288+
CHECK(d == 0x78);
289+
}
290+
291+
TEST_CASE("bit_unpack 64 -> 8x8", "[bit]") {
292+
auto const [a, b, c, d, e, f, g, h] =
293+
stdx::bit_unpack<std::uint8_t>(std::uint64_t{0x1234'5678'9abc'def0});
294+
CHECK(a == 0x12);
295+
CHECK(b == 0x34);
296+
CHECK(c == 0x56);
297+
CHECK(d == 0x78);
298+
CHECK(e == 0x9a);
299+
CHECK(f == 0xbc);
300+
CHECK(g == 0xde);
301+
CHECK(h == 0xf0);
302+
}
303+
304+
TEST_CASE("bit_pack/unpack round trip 16 <-> 8", "[bit]") {
305+
constexpr auto x = stdx::bit_pack<std::uint16_t>(0x12, 0x34);
306+
auto const [a, b] = stdx::bit_unpack<std::uint8_t>(x);
307+
CHECK(stdx::bit_pack<std::uint16_t>(a, b) == x);
308+
}
309+
310+
TEST_CASE("bit_pack/unpack round trip 32 <-> 8", "[bit]") {
311+
constexpr auto x = stdx::bit_pack<std::uint32_t>(0x12, 0x34, 0x56, 0x78);
312+
auto const [a, b, c, d] = stdx::bit_unpack<std::uint8_t>(x);
313+
CHECK(stdx::bit_pack<std::uint32_t>(a, b, c, d) == x);
314+
}
315+
316+
TEST_CASE("bit_pack/unpack round trip 64 <-> 8", "[bit]") {
317+
constexpr auto x = stdx::bit_pack<std::uint64_t>(0x12, 0x34, 0x56, 0x78,
318+
0x9a, 0xbc, 0xde, 0xf0);
319+
auto const [a, b, c, d, e, f, g, h] = stdx::bit_unpack<std::uint8_t>(x);
320+
CHECK(stdx::bit_pack<std::uint64_t>(a, b, c, d, e, f, g, h) == x);
321+
}
322+
323+
TEST_CASE("bit_pack/unpack round trip 32 <-> 16", "[bit]") {
324+
constexpr auto x = stdx::bit_pack<std::uint32_t>(0x1234, 0x5678);
325+
auto const [a, b] = stdx::bit_unpack<std::uint16_t>(x);
326+
CHECK(stdx::bit_pack<std::uint32_t>(a, b) == x);
327+
}
328+
329+
TEST_CASE("bit_pack/unpack round trip 64 <-> 16", "[bit]") {
330+
constexpr auto x =
331+
stdx::bit_pack<std::uint64_t>(0x1234, 0x5678, 0x9abc, 0xdef0);
332+
auto const [a, b, c, d] = stdx::bit_unpack<std::uint16_t>(x);
333+
CHECK(stdx::bit_pack<std::uint64_t>(a, b, c, d) == x);
334+
}
335+
336+
TEST_CASE("bit_pack/unpack round trip 64 <-> 32", "[bit]") {
337+
constexpr auto x = stdx::bit_pack<std::uint64_t>(0x1234'5678, 0x9abcdef0);
338+
auto const [a, b] = stdx::bit_unpack<std::uint32_t>(x);
339+
CHECK(stdx::bit_pack<std::uint64_t>(a, b) == x);
340+
}

0 commit comments

Comments
 (0)