more tests, allow signed int -> positive_fixint

This commit is contained in:
Kurt Sassenrath 2024-01-04 09:48:30 -08:00
parent 8f4ac703f4
commit e48ba60c68
3 changed files with 89 additions and 72 deletions

View File

@ -94,9 +94,7 @@ struct builtin_packer<bool> : builtin_packer_base {
template <std::unsigned_integral T>
struct builtin_packer<T> : builtin_packer_base {
static constexpr std::size_t rep_size(std::uint64_t value) noexcept {
constexpr auto fixint_size =
static_cast<std::uint64_t>(format::positive_fixint::mask);
if (value <= fixint_size) return 0;
if (value < 128) return 0;
auto bytes_needed =
static_cast<std::uint64_t>((std::bit_width(value) + 7) >> 3);
return std::bit_ceil(bytes_needed);
@ -121,8 +119,8 @@ struct builtin_packer<T> : builtin_packer_base {
template <std::signed_integral T>
struct builtin_packer<T> : 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;
// Probably a better way to do this; fixints
if (value < 128 && value >= -32) return 0;
auto underlying = static_cast<std::uint64_t>(value);
// save a branch; these should be cheap on modern hardware.

View File

@ -21,8 +21,9 @@
#ifndef msgpack_core_detail_packable_ranges_10d28c24498828c7
#define msgpack_core_detail_packable_ranges_10d28c24498828c7
#include "parselink/msgpack/core/detail/packable_concepts.h"
#include "parselink/msgpack/core/detail/builtin_packable_types.h"
#include "parselink/msgpack/core/detail/packable_concepts.h"
#include <ranges>
#include <tuple>
@ -31,8 +32,9 @@ namespace detail {
//
template <typename T>
concept packable_array = std::ranges::input_range<T>
&& packable<std::ranges::range_value_t<T>>;
concept packable_array =
std::ranges::input_range<T> && !std::convertible_to<T, std::string_view>
&& packable<std::ranges::range_value_t<T>>;
template <typename T>
concept key_value_pairlike = requires(T t) {

View File

@ -65,23 +65,18 @@ struct fmt::formatter<msgpack::array_desc> : fmt::formatter<std::string_view> {
namespace {
template <typename... Bytes>
constexpr std::array<std::byte, sizeof...(Bytes)> make_bytes(Bytes&&... bytes) {
return {static_cast<std::byte>(std::forward<Bytes>(bytes))...};
}
constexpr auto equal(auto a, auto b) {
return std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b));
}
template <typename T, typename U>
consteval auto within() noexcept {
return std::numeric_limits<T>::max() <= std::numeric_limits<U>::max();
template <typename T>
constexpr auto within(auto value) noexcept {
return value >= std::numeric_limits<T>::min()
&& value <= std::numeric_limits<T>::max();
}
template <typename T>
constexpr auto verify_packed(auto const& packer, auto value) {
std::array<std::byte, std::numeric_limits<T>::digits / 8> raw;
std::byte marker_for;
template <std::integral T>
constexpr auto verify_packed(auto const& packer, auto value) noexcept {
std::array<std::byte, (std::numeric_limits<T>::digits + 7) / 8> raw;
if (packer.tell() != 1 + raw.size()) return false;
auto packed = packer.subspan().subspan(1);
@ -91,37 +86,72 @@ constexpr auto verify_packed(auto const& packer, auto value) {
}
template <typename T>
auto check_unsigned() {
return rc::check([] {
auto check_signed() {
return rc::check([](T value) {
std::array<std::byte, 16> payload;
msgpack::packer packer(payload);
const auto value = *rc::gen::positive<T>();
if (!packer.pack(value)) return false;
if (value < 0x80) {
if (value < 128 && value >= -32) {
// positive_fixint/negative_fixint
return packer.tell() == 1
&& payload[0] == static_cast<std::byte>(value);
} else if (within<std::int8_t>(value)) {
return payload[0] == msgpack::format::int8::marker
&& verify_packed<std::int8_t>(packer, value);
} else if (within<std::int16_t>(value)) {
return payload[0] == msgpack::format::int16::marker
&& verify_packed<std::int16_t>(packer, value);
} else if (within<std::int32_t>(value)) {
return payload[0] == msgpack::format::int32::marker
&& verify_packed<std::int32_t>(packer, value);
} else {
return payload[0] == msgpack::format::int64::marker
&& verify_packed<std::int64_t>(packer, value);
}
});
}
template <typename T>
auto check_unsigned() {
return rc::check([](T value) {
std::array<std::byte, 16> payload;
msgpack::packer packer(payload);
if (!packer.pack(value)) return false;
if (value < 128) {
// positive_fixint
return packer.tell() == 1
&& payload[0] == static_cast<std::byte>(value);
} else if (value <= std::numeric_limits<std::uint8_t>::max()) {
// uint8
return packer.tell() == 2 && payload[0] == std::byte{0xcc}
&& T(payload[1]) == value;
} else if (value <= std::numeric_limits<std::uint16_t>::max()) {
// uint16
return payload[0] == std::byte{0xcd}
} else if (within<std::uint8_t>(value)) {
return payload[0] == msgpack::format::uint8::marker
&& verify_packed<std::uint8_t>(packer, value);
} else if (within<std::uint16_t>(value)) {
return payload[0] == msgpack::format::uint16::marker
&& verify_packed<std::uint16_t>(packer, value);
} else if (value <= std::numeric_limits<std::uint32_t>::max()) {
// uint32
return payload[0] == std::byte{0xce}
} else if (within<std::uint32_t>(value)) {
return payload[0] == msgpack::format::uint32::marker
&& verify_packed<std::uint32_t>(packer, value);
} else {
// uint64
return payload[0] == std::byte{0xcf}
return payload[0] == msgpack::format::uint64::marker
&& verify_packed<std::uint64_t>(packer, value);
}
});
}
template <std::unsigned_integral LenType, typename StrType = std::string>
auto check_string() {
return rc::check([](LenType value) {
auto str = *rc::gen::container<std::string>(
value, rc::gen::character<char>());
std::vector<std::byte> payload;
payload.resize(value + 32);
msgpack::packer packer(payload);
if (!packer.pack(str)) return false;
return true;
});
}
} // anonymous namespace
suite packer_single_format = [] {
@ -167,42 +197,29 @@ suite packer_single_format = [] {
"packer::pack<std::uint64_t>"_test = [] {
expect(check_unsigned<std::uint64_t>());
};
"packer::pack<std::int8_t>"_test = [] {
expect(check_signed<std::int8_t>());
};
"packer::pack<std::int16_t>"_test = [] {
expect(check_signed<std::int16_t>());
};
"packer::pack<std::int32_t>"_test = [] {
expect(check_signed<std::int32_t>());
};
"packer::pack<std::int64_t>"_test = [] {
expect(check_signed<std::int64_t>());
};
"packer::pack<std::string>"_test = [] {
expect(check_string<std::uint8_t>());
expect(check_string<std::uint16_t>());
};
};
#if 0
"packer::pack<bool>"_test = [] { expect(test_deduced<bool>()); };
"packer::pack<nil>"_test = [] { expect(test_deduced<msgpack::nil>()); };
"packer::pack<invalid>"_test = [] {
expect(test_deduced<msgpack::invalid>());
};
// Unsigned ints
"packer::pack<std::uint8_t>"_test = [] {
expect(test_deduced<std::uint8_t>());
};
"packer::pack<std::uint16_t>"_test = [] {
expect(test_deduced<std::uint16_t>());
};
"packer::pack<std::uint32_t>"_test = [] {
expect(test_deduced<std::uint32_t>());
};
"packer::pack<std::uint64_t>"_test = [] {
expect(test_deduced<std::uint64_t>());
};
// Signed ints
"packer::pack<std::int8_t>"_test = [] {
expect(test_deduced<std::int8_t>());
};
"packer::pack<std::int16_t>"_test = [] {
expect(test_deduced<std::int16_t>());
};
"packer::pack<std::int32_t>"_test = [] {
expect(test_deduced<std::int32_t>());
};
"packer::pack<std::int64_t>"_test = [] {
expect(test_deduced<std::int64_t>());
};
// Strings
"packer::pack<std::string_view>"_test = [] {
expect(test_deduced<std::string_view>());