From 0cafb9bcd75925bef5c5513197e6ce63d6ef0c41 Mon Sep 17 00:00:00 2001 From: Kurt Sassenrath Date: Tue, 2 Jan 2024 20:59:45 -0800 Subject: [PATCH] Additional concepts work --- .../core/detail/builtin_packable_types.h | 12 +-- .../msgpack/core/detail/packable_concepts.h | 86 +++++++++++++++++++ .../msgpack/core/detail/packable_ranges.h | 8 +- include/parselink/msgpack/core/packer.h | 14 +-- tests/msgpack/test_packer.cpp | 25 +++++- 5 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 include/parselink/msgpack/core/detail/packable_concepts.h diff --git a/include/parselink/msgpack/core/detail/builtin_packable_types.h b/include/parselink/msgpack/core/detail/builtin_packable_types.h index 1a2fb44..acd591c 100644 --- a/include/parselink/msgpack/core/detail/builtin_packable_types.h +++ b/include/parselink/msgpack/core/detail/builtin_packable_types.h @@ -18,6 +18,7 @@ #ifndef msgpack_core_detail_builtin_packable_types_41bd88d512497527 #define msgpack_core_detail_builtin_packable_types_41bd88d512497527 +#include "parselink/msgpack/core/detail/packable_concepts.h" #include "parselink/msgpack/core/format.h" #include "parselink/msgpack/util/endianness.h" @@ -284,17 +285,6 @@ struct builtin_packer : builtin_packer_base { } }; -// Requirements for builtin_packable types. -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 #endif // msgpack_core_detail_builtin_packable_types_41bd88d512497527 diff --git a/include/parselink/msgpack/core/detail/packable_concepts.h b/include/parselink/msgpack/core/detail/packable_concepts.h new file mode 100644 index 0000000..2c769f1 --- /dev/null +++ b/include/parselink/msgpack/core/detail/packable_concepts.h @@ -0,0 +1,86 @@ + +//----------------------------------------------------------------------------- +// ___ __ _ _ +// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ +// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / +// / ___/ (_| | | \__ \ __/ /__| | | | | < +// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . +// +//----------------------------------------------------------------------------- +// Author: Kurt Sassenrath +// Module: msgpack +// +// Concepts used for types that are packable by a packer. +// +// Copyright (c) 2023 Kurt Sassenrath. +// +// License TBD. +//----------------------------------------------------------------------------- +#ifndef msgpack_core_detail_packable_concepts_397b5e0ae6de61bf +#define msgpack_core_detail_packable_concepts_397b5e0ae6de61bf + +#include +#include +#include + +namespace msgpack { +namespace detail { + +// This structure models a minimal packer context. It is used to validate +// whether a particular type is considered packable or not. +struct packer_context_model { + std::byte* out; +}; + +} // namespace detail + +// Packers with built-in support will specialize builtin_packer. +template +struct builtin_packer; + +// Packers +template +struct packer_adapter; + +template typename Packer, + typename Context = detail::packer_context_model> +concept packable_with = requires(T&& value, Context& dest) { + { + Packer>::total_size(value) + } -> std::same_as; + { + Packer>::pack(value, dest) + } -> std::same_as; +}; + +template +concept custom_packable = packable_with; + +template +concept builtin_packable = packable_with; + +template +concept packable = builtin_packable || custom_packable; + +namespace detail { + + template + struct packer_impl_s; + + template + struct packer_impl_s { + using type = packer_adapter; + }; + + template + struct packer_impl_s { + using type = builtin_packer; + }; + + template + using packer_impl = packer_impl_s::type; +} // namespace detail + +} // namespace msgpack + +#endif // msgpack_core_detail_packable_concepts_397b5e0ae6de61bf diff --git a/include/parselink/msgpack/core/detail/packable_ranges.h b/include/parselink/msgpack/core/detail/packable_ranges.h index cef11ac..75115b1 100644 --- a/include/parselink/msgpack/core/detail/packable_ranges.h +++ b/include/parselink/msgpack/core/detail/packable_ranges.h @@ -21,7 +21,8 @@ #ifndef msgpack_core_detail_packable_ranges_10d28c24498828c7 #define msgpack_core_detail_packable_ranges_10d28c24498828c7 -#include "builtin_packable_types.h" +#include "parselink/msgpack/core/detail/packable_concepts.h" +#include "parselink/msgpack/core/detail/builtin_packable_types.h" #include #include @@ -31,10 +32,7 @@ namespace detail { // template concept packable_array = std::ranges::input_range - && builtin_packable>; - -template -concept tuple_like = requires(T t) { typename std::tuple_size::type; }; + && packable>; template concept key_value_pairlike = requires(T t) { diff --git a/include/parselink/msgpack/core/packer.h b/include/parselink/msgpack/core/packer.h index 05a67d4..c14064b 100644 --- a/include/parselink/msgpack/core/packer.h +++ b/include/parselink/msgpack/core/packer.h @@ -38,8 +38,10 @@ #ifndef msgpack_core_packer_1d5939e9c1498568 #define msgpack_core_packer_1d5939e9c1498568 +#include "parselink/msgpack/core/detail/packable_concepts.h" #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" @@ -54,9 +56,6 @@ namespace msgpack { template struct pack_adapter {}; -template -concept packable_type = builtin_packable; - class packer { // Replace with output_range? using BufferType = std::span; @@ -75,20 +74,21 @@ public: return std::ranges::distance(out, end); } - template + template constexpr tl::expected pack(T const& v) noexcept { auto rem = remaining(); - decltype(rem) needed = builtin_packer::total_size(v); + using packer_impl = detail::packer_impl; + decltype(rem) needed = packer_impl::total_size(v); if (needed > rem) { return tl::make_unexpected(error::out_of_space); } else { - builtin_packer::pack(v, *this); + packer_impl::pack(v, *this); return tl::monostate{}; } } }; - template + template constexpr tl::expected pack(T&& v) noexcept { context ctx{curr_, end_}; // If packing is successful, it updates iterators. diff --git a/tests/msgpack/test_packer.cpp b/tests/msgpack/test_packer.cpp index 66a36f0..8e7fd2a 100644 --- a/tests/msgpack/test_packer.cpp +++ b/tests/msgpack/test_packer.cpp @@ -292,7 +292,7 @@ bool test_deduced() noexcept { } // anonymous namespace -suite packer = [] { +suite packer_single_format = [] { "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { expect(test_deduced()); }; "packer::pack"_test = [] { @@ -387,3 +387,26 @@ suite packer = [] { expect(test_deduced()); }; }; + +suite packer_ranges = [] { + "packer::pack>"_test = [] { + constexpr auto data_array = std::to_array({5, 10, 15, 20}); + constexpr auto expected = + make_bytes(0x94, 0xd0, 0x05, 0xd0, 0xa, 0xd0, 0xf, 0xd0, 0x14); + + { + std::array payload; + msgpack::packer packer(payload); + expect(!!packer.pack(data_array)); + expect(std::ranges::equal(payload, expected)); + } + + { + std::span data_span{data_array}; + std::array payload; + msgpack::packer packer(payload); + expect(!!packer.pack(data_span)); + expect(std::ranges::equal(payload, expected)); + } + }; +};