Add msgpack packer support for ranges of objects.

This commit is contained in:
Kurt Sassenrath 2023-12-30 19:18:09 -08:00
parent cb2b5b47b0
commit 3d7ba40289
3 changed files with 64 additions and 51 deletions

View File

@ -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 <typename T>
concept byte_range = std::ranges::contiguous_range<T>
@ -66,25 +70,23 @@ struct builtin_packer;
template <>
struct builtin_packer<invalid> : 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<nil> : 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<bool> : builtin_packer_base {
static constexpr auto pack(bool value, auto out) noexcept -> decltype(out) {
*out++ = format::boolean::marker | static_cast<std::byte>(value);
return out;
static constexpr void pack(bool value, auto& packer) noexcept {
*(packer.out)++ =
format::boolean::marker | static_cast<std::byte>(value);
}
};
@ -109,10 +111,9 @@ struct builtin_packer<T> : 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<T> : 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<T> : 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<std::string_view> : 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<std::byte const*>(&*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<array_desc> : 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<map_desc> : 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<map_desc> */
/* : builtin_packer_base<format::type::map> {}; */
// Requirements for builtin_packable types.
template <typename T>
concept builtin_packable = requires(T const& value, std::byte* dest) {
{ builtin_packer<T>::total_size(value) } -> std::same_as<std::size_t>;
{ builtin_packer<T>::pack(value, dest) } -> std::same_as<decltype(dest)>;
template <typename T, typename Packer = detail::dummy_packer>
concept builtin_packable = requires(T&& value, Packer& dest) {
{
builtin_packer<std::remove_cvref_t<T>>::total_size(value)
} -> std::same_as<std::size_t>;
{
builtin_packer<std::remove_cvref_t<T>>::pack(value, dest)
} -> std::same_as<void>;
};
} // namespace msgpack

View File

@ -31,11 +31,23 @@ template <typename T>
concept packable_range = std::ranges::input_range<T>
&& builtin_packable<std::ranges::range_value_t<T>>;
static_assert(packable_range<std::array<std::string_view, 5>>);
static_assert(packable_range<std::span<std::string_view>>);
template <packable_range T>
struct builtin_packer<T> {
struct builtin_packer<T> : 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<array_desc>::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

View File

@ -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 <packable_type T>
constexpr tl::expected<tl::monostate, error> pack(T&& v) noexcept {
using diff_type =
std::iterator_traits<decltype(curr_)>::difference_type;
constexpr tl::expected<tl::monostate, error> pack(T const& v) noexcept {
auto rem = remaining();
decltype(rem) needed = builtin_packer<T>::total_size(v);
if (needed > rem) {
@ -93,10 +92,12 @@ public:
constexpr tl::expected<tl::monostate, error> pack(T&& v) noexcept {
context ctx{curr_, end_};
// If packing is successful, it updates iterators.
return ctx.pack(std::forward<T>(v)).map([&]{
auto ret = ctx.pack(std::forward<T>(v));
if (!!ret) {
curr_ = ctx.out;
end_ = ctx.end;
});
}
return ret;
}
constexpr auto tell() const noexcept {