Add msgpack packer support for ranges of objects.
This commit is contained in:
parent
cb2b5b47b0
commit
3d7ba40289
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user