diff --git a/include/parselink/msgpack/core/detail/builtin_packable_types.h b/include/parselink/msgpack/core/detail/builtin_packable_types.h index 57f43fb..1dde8a1 100644 --- a/include/parselink/msgpack/core/detail/builtin_packable_types.h +++ b/include/parselink/msgpack/core/detail/builtin_packable_types.h @@ -38,39 +38,59 @@ constexpr auto pack_integral(T value, Itr out, std::size_t sz) noexcept { return out; } -// This structure helps to derive sizes needed to optimally represent the -// given value (for integer formats) or the length (variable-length formats). -template -struct builtin_pack_helper { -#if 0 - // Returns the number of bytes needed to store the representation of a - // value in the associated msgpack format. - static constexpr std::size_t rep_bytes(auto /*value*/) noexcept { +// Defines a range of bytes for binary formats. +template +concept byte_range = std::ranges::contiguous_range + && std::same_as, std::byte>; + +} // namespace detail + +struct builtin_packer_base { + static constexpr std::size_t rep_size(auto const&) noexcept { return 0; } + + static constexpr std::size_t len_size(auto const& value) noexcept { return 0; } - // Returns the number of bytes needed to store the length of a value for - // a given format. For fixed-size data, this will be zero. - static constexpr std::size_t len_bytes(auto /*value*/) noexcept { - return 0; + static constexpr auto total_size(auto const& value) noexcept { + return 1 + len_size(value) + rep_size(value); } +}; - // Returns the total number of bytes needed to store a value for a given - // format. - static constexpr std::size_t total_bytes(auto value) noexcept { - return 1 + rep_bytes(value) + len_bytes(value); - } +template +struct builtin_packer; - // Get the marker. Defaults to invalid in this structure. - static constexpr std::byte marker(auto value) noexcept { - return format::invalid::marker; +//////////////////////////////////////////////////////////////////////////////// +// Built-in packer specializations +//////////////////////////////////////////////////////////////////////////////// + +template <> +struct builtin_packer : builtin_packer_base { + static constexpr auto pack(auto, auto out) noexcept -> decltype(out) { + *out++ = format::invalid::marker; + return out; } -#endif }; template <> -struct builtin_pack_helper { - static constexpr std::size_t rep_bytes(std::uint64_t value) noexcept { +struct builtin_packer : builtin_packer_base { + static constexpr auto pack(auto, auto out) noexcept -> decltype(out) { + *out++ = format::nil::marker; + return out; + } +}; + +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; + } +}; + +template +struct builtin_packer : builtin_packer_base { + static constexpr std::size_t rep_size(std::uint64_t value) noexcept { constexpr auto fixint_size = static_cast(format::positive_fixint::mask); if (value <= fixint_size) return 0; @@ -80,7 +100,7 @@ struct builtin_pack_helper { } static constexpr std::byte marker(std::uint64_t value) noexcept { - switch (rep_bytes(value)) { + switch (rep_size(value)) { case 0: return static_cast(value); case 1: return format::uint8::marker; case 2: return format::uint16::marker; @@ -88,11 +108,17 @@ struct builtin_pack_helper { default: return format::uint64::marker; } } + + static constexpr auto pack( + T const& value, auto out) noexcept -> decltype(out) { + *out++ = marker(value); + return detail::pack_integral(value, out, rep_size(value)); + } }; -template <> -struct builtin_pack_helper { - static constexpr std::size_t rep_bytes(std::int64_t value) noexcept { +template +struct builtin_packer : builtin_packer_base { + static constexpr std::size_t rep_size(std::int64_t value) noexcept { // Probably a better way to do this. if (value < 0 && value >= -32) return 0; auto underlying = static_cast(value); @@ -109,7 +135,7 @@ struct builtin_pack_helper { } static constexpr std::byte marker(std::int64_t value) noexcept { - switch (rep_bytes(value)) { + switch (rep_size(value)) { case 0: return static_cast(value); case 1: return format::int8::marker; case 2: return format::int16::marker; @@ -117,176 +143,40 @@ struct builtin_pack_helper { default: return format::int64::marker; } } -}; -template <> -struct builtin_pack_helper { - static constexpr std::size_t rep_bytes(nil) noexcept { return 0; } - - static constexpr std::byte marker(nil) noexcept { - return format::nil::marker; - } -}; - -template <> -struct builtin_pack_helper { - static constexpr std::size_t rep_bytes(invalid) noexcept { return 0; } - - static constexpr std::byte marker(invalid) noexcept { - return format::invalid::marker; - } -}; - -template -concept byte_range = std::ranges::contiguous_range - && std::same_as, std::byte>; - -template <> -struct builtin_pack_helper { - static constexpr uint32_t max_payload_length = 4; - - static constexpr std::size_t rep_bytes( - byte_range auto const& value) noexcept { - return std::ranges::size(value); - } - - static constexpr std::size_t len_bytes( - byte_range auto const& value) noexcept { - auto const len = rep_bytes(value); - auto const rounded_bytes = std::bit_ceil(static_cast( - ((std::bit_width(std::ranges::size(value)) + 7) >> 3))); - return std::min(max_payload_length, rounded_bytes); - } - - static constexpr auto marker(byte_range auto const& value) noexcept { - switch (len_bytes(value)) { - case 1: return format::bin8::marker; - case 2: return format::bin16::marker; - case 4: - default: return format::bin32::marker; - } - } -}; - -template <> -struct builtin_pack_helper { - static constexpr uint32_t max_payload_length = 4; - - static constexpr std::size_t rep_bytes(auto const& value) noexcept { - return std::size(value); - } - - static constexpr std::size_t len_bytes(auto const& value) noexcept { - auto const len = std::size(value); - if (len <= std::uint32_t(format::fixstr::mask)) return 0; - return std::min(max_payload_length, - std::bit_ceil(std::uint32_t((std::bit_width(len) + 7) >> 3))); - } - - static constexpr auto marker(auto const& value) noexcept { - switch (len_bytes(value)) { - case 0: - return format::fixstr::marker - | static_cast(std::size(value)); - case 1: return format::str8::marker; - case 2: return format::str16::marker; - case 4: - default: return format::str32::marker; - } - } -}; - -template <> -struct builtin_pack_helper { - static constexpr std::size_t rep_bytes(auto const&) noexcept { return 0; } - - static constexpr auto marker(auto const& value) noexcept { - return format::boolean::marker - | (value ? std::byte{0x01} : std::byte{}); - } -}; - -} // namespace detail - -template -struct builtin_packer_base { - static constexpr auto format = F; - using helper = detail::builtin_pack_helper; - - static constexpr std::size_t rep_size(auto const& value) noexcept { - return helper::rep_bytes(value); - } - - static constexpr std::size_t len_size(auto const& value) noexcept { - if constexpr (requires { helper::len_bytes(value); }) { - return helper::len_bytes(value); - } else { - return 0; - } - } - - static constexpr auto total_size(auto const& value) noexcept { - return 1 + len_size(value) + rep_size(value); - } - - static constexpr auto marker(auto const& value) noexcept { - return helper::marker(value); - } -}; - -template -struct builtin_packer; - -//////////////////////////////////////////////////////////////////////////////// -// Built-in packer specializations -//////////////////////////////////////////////////////////////////////////////// - -template <> -struct builtin_packer : builtin_packer_base { - static constexpr auto pack(auto, auto out) noexcept -> decltype(out) { - *out++ = format::invalid::marker; - return out; - } -}; - -template <> -struct builtin_packer : builtin_packer_base { - static constexpr auto pack(auto, auto out) noexcept -> decltype(out) { - *out++ = format::nil::marker; - return out; - } -}; - -template <> -struct builtin_packer : builtin_packer_base { - static constexpr auto pack(bool value, auto out) noexcept -> decltype(out) { - *out++ = marker(value); - return out; - } -}; - -template -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)); - } -}; - -template -struct builtin_packer : builtin_packer_base { - static constexpr auto pack(T const& value, auto out) noexcept - -> decltype(out) { + static constexpr auto pack( + T const& value, auto out) noexcept -> decltype(out) { *out++ = marker(value); return detail::pack_integral(value, out, rep_size(value)); } }; template -struct builtin_packer : builtin_packer_base { - static constexpr auto pack(T const& value, auto out) noexcept - -> decltype(out) { +struct builtin_packer : builtin_packer_base { + static constexpr uint32_t max_payload_length = 4; + + static constexpr std::size_t rep_size(T const& value) noexcept { + return std::ranges::size(value); + } + + static constexpr std::size_t len_size(T const& value) noexcept { + auto const len = rep_size(value); + auto const rounded_bytes = std::bit_ceil(static_cast( + ((std::bit_width(std::ranges::size(value)) + 7) >> 3))); + return std::min(max_payload_length, rounded_bytes); + } + + static constexpr auto marker(T const& value) noexcept { + switch (len_size(value)) { + case 1: return format::bin8::marker; + case 2: return format::bin16::marker; + case 4: + default: return format::bin32::marker; + } + } + + 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)); @@ -295,10 +185,34 @@ struct builtin_packer : builtin_packer_base { }; template <> -struct builtin_packer - : builtin_packer_base { - static constexpr auto pack(std::string_view value, auto out) noexcept - -> decltype(out) { +struct builtin_packer : builtin_packer_base { + static constexpr uint32_t max_payload_length = 4; + + static constexpr std::size_t rep_size(std::string_view value) noexcept { + return std::size(value); + } + + static constexpr std::size_t len_size(std::string_view value) noexcept { + auto const len = std::size(value); + if (len <= std::uint32_t(format::fixstr::mask)) return 0; + return std::min(max_payload_length, + std::bit_ceil(std::uint32_t((std::bit_width(len) + 7) >> 3))); + } + + static constexpr auto marker(std::string_view value) noexcept { + switch (len_size(value)) { + case 0: + return format::fixstr::marker + | static_cast(rep_size(value)); + case 1: return format::str8::marker; + case 2: return format::str16::marker; + case 4: + default: return format::str32::marker; + } + } + + static constexpr auto pack( + std::string_view value, auto out) noexcept -> decltype(out) { *out++ = marker(value); auto const size = std::size(value); out = detail::pack_integral(size, out, len_size(value)); @@ -307,16 +221,18 @@ struct builtin_packer } }; +// All things that convert to std::string_view should use the string_view +// overload of builtin_packer. template T> struct builtin_packer : builtin_packer {}; -template <> -struct builtin_packer - : builtin_packer_base {}; +/* template <> */ +/* struct builtin_packer */ +/* : builtin_packer_base {}; */ -template <> -struct builtin_packer - : builtin_packer_base {}; +/* template <> */ +/* struct builtin_packer */ +/* : builtin_packer_base {}; */ // Requirements for builtin_packable types. template diff --git a/include/parselink/msgpack/core/detail/packable_ranges.h b/include/parselink/msgpack/core/detail/packable_ranges.h index 394e0c7..93b60f3 100644 --- a/include/parselink/msgpack/core/detail/packable_ranges.h +++ b/include/parselink/msgpack/core/detail/packable_ranges.h @@ -35,7 +35,8 @@ static_assert(packable_range>); static_assert(packable_range>); template -struct builtin_packer {}; +struct builtin_packer { +}; } // namespace msgpack