#pragma once #include #include #include #include "compat/assert.hpp" namespace floormat::Pack { template struct Bits_; } // namespace floormat::Pack namespace floormat::detail_Pack { using namespace floormat::Pack; template struct check_size_overflow; template struct check_size_overflow, Xs...> { static_assert(std::is_same_v); static constexpr auto acc = Sum + size_t{N}; using next_check = check_size_overflow; static constexpr auto size = next_check::size; static constexpr bool result = next_check::result; }; template struct check_size_overflow { static constexpr size_t size = Sum; static constexpr bool result = Sum <= sizeof(T)*8; }; template struct Storage { static_assert(CAPACITY <= sizeof(T)*8); using Type = T; static constexpr size_t Capacity = CAPACITY; T value; template constexpr T get() const { static_assert(N > 0); static_assert(N <= sizeof(T)*8); static_assert(N <= Capacity); return T(value & (T(1) << N) - T(1)); } template constexpr T advance() const { static_assert(N <= sizeof(T)*8); static_assert(N <= Capacity); return T(value >> N); } constexpr bool operator==(const Storage&) const noexcept = default; [[nodiscard]] constexpr inline bool check_zero() const { return value == T(0); } template using next = Storage; }; template struct Storage { using Type = T; static constexpr size_t Capacity = 0; T value; template [[maybe_unused]] constexpr T get() const = delete; template [[maybe_unused]] constexpr T advance() const = delete; constexpr bool operator==(const Storage&) const noexcept = default; [[nodiscard]] constexpr inline bool check_zero() const { return true; } template struct next { static_assert(N == 0, "reading past the end"); static_assert(N != 0, "reading past the end"); }; }; template struct make_tuple_type_ { template using index_to_type = T; template struct aux; template struct aux> { static_assert(sizeof...(Is) > 0); using type = std::tuple...>; }; using Seq = typename aux>::type; }; template using make_tuple_type = typename make_tuple_type_::Seq; template static void assign_to_tuple(Place&, Storage st, std::index_sequence<>) { fm_assert(st.check_zero()); } template static void assign_to_tuple(Place& p, Storage st, std::index_sequence) { using std::get; get(p) = st.template get(st); assign_to_tuple(p, st.template advance(), std::index_sequence{}); } } // namespace floormat::detail_Pack namespace floormat::Pack { template struct Bits_ final { static_assert(std::is_fundamental_v); static_assert(N > 0); static_assert(N < sizeof(T)*8); using type = T; static constexpr auto bits = N; }; } // namespace floormat::Pack