diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2024-01-12 21:51:38 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2024-01-13 02:29:08 +0100 |
commit | 84b8a220091e64bb1dd6c66fa49edac673df4ddb (patch) | |
tree | 2f1ad37a2d1886bf4cb2ba06fb4fde90d6f55c4f /serialize | |
parent | f18a3b8de7bfff4f62f6d19153c98635988832b8 (diff) |
serialize/packbits: wip
Diffstat (limited to 'serialize')
-rw-r--r-- | serialize/packbits.cpp | 55 | ||||
-rw-r--r-- | serialize/packbits.hpp | 98 |
2 files changed, 153 insertions, 0 deletions
diff --git a/serialize/packbits.cpp b/serialize/packbits.cpp new file mode 100644 index 00000000..81c6c172 --- /dev/null +++ b/serialize/packbits.cpp @@ -0,0 +1,55 @@ +#include "packbits.hpp" + +namespace floormat { + +using namespace floormat::detail_Pack; + +namespace { + +constexpr bool test1() +{ + using S1 = Storage<uint8_t, 8>; + S1 st1{0b10111011}; + fm_assert(st1.value == 0b10111011); + + fm_assert(st1.get<3>() == 0b011); + using S2 = typename S1::next<3>; + S2 st2{st1.advance<3>()}; + static_assert(std::is_same_v<S2, Storage<uint8_t, 5>>); + fm_assert(st2.value == 0b10111); + + return true; +} +static_assert(test1()); + +namespace test2 { +template<size_t Val> using ibits = Bits_<uint16_t, Val>; +using foo1 = ibits<2>; +using foo2 = ibits<10>; +using foo3 = ibits<4>; +using bar1 = check_size_overflow<uint16_t, 0, foo1, foo2>; +static_assert(bar1::result); +static_assert(bar1::size == 12); + +using bar2 = check_size_overflow<uint16_t, 0, foo2>; +static_assert(bar2::result); +static_assert(bar2::size == 10); + +using bar3 = check_size_overflow<uint16_t, 0, foo1, foo2, foo3>; +static_assert(bar3::result); +static_assert(bar3::size == 16); + +using foo4 = ibits<1>; +using bar4 = check_size_overflow<uint16_t, 0, foo1, foo2, foo3, foo4>; +static_assert(!bar4::result); +static_assert(bar4::size == 17); + +using foo5 = ibits<20>; +using bar5 = check_size_overflow<uint16_t, 0, foo1, foo2, foo3, foo4, foo5>; +static_assert(!bar5::result); +static_assert(bar5::size == 37); +} // namespace test2 + +} // namespace + +} // namespace floormat diff --git a/serialize/packbits.hpp b/serialize/packbits.hpp new file mode 100644 index 00000000..6e388846 --- /dev/null +++ b/serialize/packbits.hpp @@ -0,0 +1,98 @@ +#pragma once +#include "compat/assert.hpp" +#include <type_traits> +#include <concepts> + +namespace floormat::Pack { +template<std::unsigned_integral T, uint8_t N> struct Bits_; +} // namespace floormat::Pack + +namespace floormat::detail_Pack { + +using namespace floormat::Pack; +template<std::unsigned_integral T, size_t Sum, typename... Xs> struct check_size_overflow; + +template<std::unsigned_integral T, std::unsigned_integral U, size_t Sum, uint8_t N, typename... Xs> +struct check_size_overflow<T, Sum, Bits_<U, N>, Xs...> +{ + static_assert(std::is_same_v<T, U>); + static constexpr auto acc = Sum + size_t{N}; + using next_check = check_size_overflow<T, acc, Xs...>; + static constexpr auto size = next_check::size; + static constexpr bool result = next_check::result; +}; + +template<std::unsigned_integral T, size_t Sum> +struct check_size_overflow<T, Sum> +{ + static constexpr size_t size = Sum; + static constexpr bool result = Sum <= sizeof(T)*8; +}; + +template<std::unsigned_integral T, size_t Capacity> +struct Storage +{ + static_assert(Capacity <= sizeof(T)*8); + T value; + + template<size_t N> + constexpr T get() + { + static_assert(N <= sizeof(T)*8); + static_assert(N <= Capacity); + return T(value & (T(1) << N) - T(1)); + } + + template<size_t N> + constexpr T advance() + { + static_assert(N <= sizeof(T)*8); + static_assert(N <= Capacity); + return T(value >> N); + } + + template<size_t N> [[maybe_unused]] constexpr bool check_zero() = delete; + + template<size_t N> + using next = Storage<T, Capacity - N>; +}; + +template<std::unsigned_integral T> +struct Storage<T, 0> +{ + T value; + + template<size_t N> [[maybe_unused]] constexpr T get() = delete; + template<size_t N> [[maybe_unused]] constexpr T advance() = delete; + + template<size_t N> constexpr inline bool check_zero() + { + fm_assert(value == T(0)); + return true; + } + + template<size_t N> struct next + { + static_assert(!std::is_same_v<T, void>, "reading past the end"); + static_assert( std::is_same_v<T, void>, "can't happen!"); + }; +}; + +} // namespace floormat::detail_Pack + +namespace floormat::Pack { + +template<std::unsigned_integral T, uint8_t N> +struct Bits_ final +{ + static_assert(std::is_fundamental_v<T>); + static_assert(N > 0); + static_assert(N < sizeof(T)*8); + + using type = T; + static constexpr auto bits = N; +}; + + + +} // namespace floormat::Pack |