diff options
Diffstat (limited to 'serialize/packbits-write.hpp')
| -rw-r--r-- | serialize/packbits-write.hpp | 63 |
1 files changed, 53 insertions, 10 deletions
diff --git a/serialize/packbits-write.hpp b/serialize/packbits-write.hpp index 34fc140f..faa3ff00 100644 --- a/serialize/packbits-write.hpp +++ b/serialize/packbits-write.hpp @@ -1,28 +1,71 @@ #pragma once +#include "compat/assert.hpp" +#include <type_traits> +#include <utility> #include <concepts> namespace floormat::detail_Pack_output { -template<std::unsigned_integral T> +template<size_t N> +struct output_bits final +{ + static_assert(N > 0); + static_assert(N < sizeof(size_t)*8); + + static constexpr size_t length = N; +}; + +template<std::unsigned_integral T, size_t CAPACITY> struct output { - T value = 0; - uint8_t capacity = sizeof(T)*8; + static_assert(std::is_fundamental_v<T>); + static_assert(CAPACITY <= sizeof(T)*8); + static constexpr size_t Capacity = CAPACITY; + + T value{0}; - constexpr inline output next(T x, uint8_t bits) const + template<size_t N> + constexpr T set(T x, output_bits<N>) const { - fm_assert(bits > 0 && bits <= capacity); - auto val = value; - val <<= bits; - T x_ = T(x & (T{1} << bits)- T{1}); + static_assert(N <= CAPACITY, "data type too small"); + static_assert(N > 0); + T value_{value}; + if constexpr(CAPACITY != sizeof(T)*8) + value_ <<= CAPACITY; + auto x_ = T(x & (T{1}<<N)-T{1}); fm_assert(x_ == x); - val |= x_; - return { val | x_, capacity - bits }; + value_ |= x_; + return value_; } + + template<size_t N> + struct next_ + { + static_assert(N > 0); + static_assert(N <= CAPACITY); + using type = output<T, CAPACITY - N>; + }; + + template<size_t N> using next = typename next_<N>::type; }; +template<typename T, size_t N> +using output_field = std::pair<T, output_bits<N>>; +template<typename... Ts> struct empty_pack_tuple {}; // todo copypasta +template<typename T, size_t Left, size_t F, typename... Fields> +constexpr T write_(output<T, Left> st, output_field<T, F> field, Fields... fields) +{ + T value = st.set(field.first, field.second); + using next = typename output<T, Left>::template next<F>; + return write_(next{value}, fields...); +} +template<typename T, size_t Left> +constexpr T write_(output<T, Left> st) +{ + return st.value; +} } // namespace floormat::detail_Pack_output |
