#pragma once #include "packbits-impl.hpp" #include "compat/reverse-index-sequence.hpp" #include #include #include #include namespace floormat::Pack_impl { template struct output { static_assert(LEFT >= 0); static_assert(LEFT <= CAPACITY); static_assert(CAPACITY <= sizeof(T)*8); static constexpr size_t Capacity = CAPACITY, Left = LEFT; T value{0}; }; template struct output_field { static_assert(LENGTH > 0); static_assert(LENGTH <= sizeof(T)*8); static constexpr size_t Length = LENGTH; T value; }; template struct is_output_field : std::bool_constant {}; template struct is_output_field> : std::bool_constant { static_assert(N > 0); }; template requires requires (const Field& x) { { size_t{Field::Length} > 0 }; sizeof(std::decay_t); requires std::unsigned_integral>; } struct is_output_field : std::bool_constant {}; template constexpr CORRADE_ALWAYS_INLINE T write_(const Tuple& tuple, output st, std::index_sequence) { static_assert(Capacity > 0); static_assert(Capacity <= sizeof(T)*8); static_assert(Left > 0, "too many bits to write"); static_assert(Left <= Capacity, "too many bits to write"); static_assert(I < std::tuple_size_v, "too few tuple elements"); static_assert(is_output_field>>{}, "tuple element must be output_field"); constexpr size_t N = std::tuple_element_t::Length; static_assert(N <= Left, "too many bits to write"); T x = std::get(tuple).value; if (!((size_t)std::bit_width(x) <= N)) [[unlikely]] throw_on_write_input_bit_overflow(); T value = T(T(st.value << N) | x); return write_(tuple, output{value}, std::index_sequence{}); } template constexpr CORRADE_ALWAYS_INLINE T write_(const Tuple&, output st, std::index_sequence<>) { return st.value; } } // namespace floormat::Pack_impl namespace floormat { template requires requires (const Tuple& tuple) { std::tuple_size_v > 0uz; Pack_impl::is_output_field(tuple))>>::value; } [[nodiscard]] constexpr auto pack_write(const Tuple& tuple) { using Field = std::decay_t>; static_assert(Pack_impl::is_output_field{}); using T = std::decay_t().value)>; constexpr size_t nbits = sizeof(T)*8, tuple_size = std::tuple_size_v; return Pack_impl::write_(tuple, Pack_impl::output{T{0}}, make_reverse_index_sequence{}); } constexpr uint8_t pack_write(const std::tuple<>&) = delete; } // namespace floormat