From 3d7ba40289f46526db4e5269f32655e0b242b47b Mon Sep 17 00:00:00 2001 From: Kurt Sassenrath Date: Sat, 30 Dec 2023 19:18:09 -0800 Subject: [PATCH] Add msgpack packer support for ranges of objects. --- .../core/detail/builtin_packable_types.h | 84 +++++++++---------- .../msgpack/core/detail/packable_ranges.h | 20 ++++- include/parselink/msgpack/core/packer.h | 11 +-- 3 files changed, 64 insertions(+), 51 deletions(-) diff --git a/include/parselink/msgpack/core/detail/builtin_packable_types.h b/include/parselink/msgpack/core/detail/builtin_packable_types.h index dcc3777..1a2fb44 100644 --- a/include/parselink/msgpack/core/detail/builtin_packable_types.h +++ b/include/parselink/msgpack/core/detail/builtin_packable_types.h @@ -38,6 +38,10 @@ constexpr auto pack_integral(T value, Itr out, std::size_t sz) noexcept { return out; } +struct dummy_packer { + std::byte* out; +}; + // Defines a range of bytes for binary formats. template concept byte_range = std::ranges::contiguous_range @@ -66,25 +70,23 @@ struct builtin_packer; template <> struct builtin_packer : builtin_packer_base { - static constexpr auto pack(auto, auto out) noexcept -> decltype(out) { - *out++ = format::invalid::marker; - return out; + static constexpr void pack(auto, auto& packer) noexcept { + *(packer.out)++ = format::invalid::marker; } }; template <> struct builtin_packer : builtin_packer_base { - static constexpr auto pack(auto, auto out) noexcept -> decltype(out) { - *out++ = format::nil::marker; - return out; + static constexpr void pack(auto, auto& packer) noexcept { + *(packer.out)++ = format::nil::marker; } }; template <> struct builtin_packer : builtin_packer_base { - static constexpr auto pack(bool value, auto out) noexcept -> decltype(out) { - *out++ = format::boolean::marker | static_cast(value); - return out; + static constexpr void pack(bool value, auto& packer) noexcept { + *(packer.out)++ = + format::boolean::marker | static_cast(value); } }; @@ -109,10 +111,9 @@ struct builtin_packer : builtin_packer_base { } } - static constexpr auto pack( - T const& value, auto out) noexcept -> decltype(out) { - *out++ = marker(value); - return detail::pack_integral(value, out, rep_size(value)); + static constexpr void pack(T const& value, auto& packer) noexcept { + *(packer.out)++ = marker(value); + packer.out = detail::pack_integral(value, packer.out, rep_size(value)); } }; @@ -144,10 +145,9 @@ struct builtin_packer : builtin_packer_base { } } - static constexpr auto pack( - T const& value, auto out) noexcept -> decltype(out) { - *out++ = marker(value); - return detail::pack_integral(value, out, rep_size(value)); + static constexpr void pack(T const& value, auto& packer) noexcept { + *(packer.out)++ = marker(value); + packer.out = detail::pack_integral(value, packer.out, rep_size(value)); } }; @@ -175,12 +175,11 @@ struct builtin_packer : builtin_packer_base { } } - static constexpr auto pack( - T const& value, auto out) noexcept -> decltype(out) { - *out++ = marker(value); - out = detail::pack_integral( - std::ranges::size(value), out, len_size(value)); - return std::ranges::copy(value, out).out; + static constexpr void pack(T const& value, auto& packer) noexcept { + *(packer.out)++ = marker(value); + packer.out = detail::pack_integral( + std::ranges::size(value), packer.out, len_size(value)); + packer.out = std::ranges::copy(value, packer.out).out; } }; @@ -211,13 +210,12 @@ struct builtin_packer : builtin_packer_base { } } - static constexpr auto pack( - std::string_view value, auto out) noexcept -> decltype(out) { - *out++ = marker(value); + static constexpr void pack(std::string_view value, auto& packer) noexcept { + *(packer.out)++ = marker(value); auto const size = std::size(value); - out = detail::pack_integral(size, out, len_size(value)); + packer.out = detail::pack_integral(size, packer.out, len_size(value)); auto const* beg = reinterpret_cast(&*value.begin()); - return std::ranges::copy(beg, beg + size, out).out; + packer.out = std::ranges::copy(beg, beg + size, packer.out).out; } }; @@ -249,9 +247,10 @@ struct builtin_packer : builtin_packer_base { } } - static constexpr auto pack(array_desc value, auto out) noexcept { - *out++ = marker(value); - return detail::pack_integral(value.count, out, rep_size(value)); + static constexpr auto pack(array_desc value, auto& packer) noexcept { + *(packer.out)++ = marker(value); + packer.out = + detail::pack_integral(value.count, packer.out, rep_size(value)); } }; @@ -278,21 +277,22 @@ struct builtin_packer : builtin_packer_base { } } - static constexpr auto pack(map_desc value, auto out) noexcept { - *out++ = marker(value); - return detail::pack_integral(value.count, out, rep_size(value)); + static constexpr void pack(map_desc value, auto& packer) noexcept { + *(packer.out)++ = marker(value); + packer.out = + detail::pack_integral(value.count, packer.out, rep_size(value)); } }; -/* template <> */ -/* struct builtin_packer */ -/* : builtin_packer_base {}; */ - // Requirements for builtin_packable types. -template -concept builtin_packable = requires(T const& value, std::byte* dest) { - { builtin_packer::total_size(value) } -> std::same_as; - { builtin_packer::pack(value, dest) } -> std::same_as; +template +concept builtin_packable = requires(T&& value, Packer& dest) { + { + builtin_packer>::total_size(value) + } -> std::same_as; + { + builtin_packer>::pack(value, dest) + } -> std::same_as; }; } // namespace msgpack diff --git a/include/parselink/msgpack/core/detail/packable_ranges.h b/include/parselink/msgpack/core/detail/packable_ranges.h index 93b60f3..8e1ef3c 100644 --- a/include/parselink/msgpack/core/detail/packable_ranges.h +++ b/include/parselink/msgpack/core/detail/packable_ranges.h @@ -31,11 +31,23 @@ template concept packable_range = std::ranges::input_range && builtin_packable>; -static_assert(packable_range>); -static_assert(packable_range>); - template -struct builtin_packer { +struct builtin_packer : builtin_packer_base { + static constexpr std::size_t rep_size(T const& value) { + return std::ranges::size(value); + } + + static constexpr auto marker(T const& value) { + array_desc desc(rep_size(value)); + return builtin_packer::marker(desc); + } + + static constexpr void pack(T const& value, auto& packer) noexcept { + packer.pack(array_desc(rep_size(value))); + for (auto const& element : value) { + packer.pack(element); + } + } }; } // namespace msgpack diff --git a/include/parselink/msgpack/core/packer.h b/include/parselink/msgpack/core/packer.h index 6998ee6..05a67d4 100644 --- a/include/parselink/msgpack/core/packer.h +++ b/include/parselink/msgpack/core/packer.h @@ -39,6 +39,7 @@ #define msgpack_core_packer_1d5939e9c1498568 #include "parselink/msgpack/core/detail/builtin_packable_types.h" +#include "parselink/msgpack/core/detail/packable_ranges.h" #include "parselink/msgpack/core/error.h" #include "parselink/msgpack/core/format.h" #include "parselink/msgpack/util/endianness.h" @@ -75,9 +76,7 @@ public: } template - constexpr tl::expected pack(T&& v) noexcept { - using diff_type = - std::iterator_traits::difference_type; + constexpr tl::expected pack(T const& v) noexcept { auto rem = remaining(); decltype(rem) needed = builtin_packer::total_size(v); if (needed > rem) { @@ -93,10 +92,12 @@ public: constexpr tl::expected pack(T&& v) noexcept { context ctx{curr_, end_}; // If packing is successful, it updates iterators. - return ctx.pack(std::forward(v)).map([&]{ + auto ret = ctx.pack(std::forward(v)); + if (!!ret) { curr_ = ctx.out; end_ = ctx.end; - }); + } + return ret; } constexpr auto tell() const noexcept {