diff --git a/deps/saucer/include/glaze/api/api.hpp b/deps/saucer/include/glaze/api/api.hpp index b7ce73e..1e6690f 100644 --- a/deps/saucer/include/glaze/api/api.hpp +++ b/deps/saucer/include/glaze/api/api.hpp @@ -100,7 +100,7 @@ namespace glz auto tuple_args = std::forward_as_tuple(std::forward(args)...); - for_each([&](auto I) { std::get(arguments) = &std::get(tuple_args); }); + for_each([&]() { std::get(arguments) = &std::get(tuple_args); }); if constexpr (std::is_pointer_v) { void* ptr{}; diff --git a/deps/saucer/include/glaze/api/hash.hpp b/deps/saucer/include/glaze/api/hash.hpp index c34f02d..09c220c 100644 --- a/deps/saucer/include/glaze/api/hash.hpp +++ b/deps/saucer/include/glaze/api/hash.hpp @@ -77,10 +77,6 @@ namespace glz static constexpr type value{}; static constexpr const std::string_view get() { return {value.data, num_digits(x)}; } }; - - /* instantiate numeric_string::value as needed for different numbers */ - template - constexpr typename numeric_string::type numeric_string::value; } template diff --git a/deps/saucer/include/glaze/api/impl.hpp b/deps/saucer/include/glaze/api/impl.hpp index 4f4ab21..1422f17 100644 --- a/deps/saucer/include/glaze/api/impl.hpp +++ b/deps/saucer/include/glaze/api/impl.hpp @@ -19,8 +19,8 @@ #include "glaze/api/std/vector.hpp" #include "glaze/api/tuplet.hpp" #include "glaze/api/type_support.hpp" -#include "glaze/binary/read.hpp" -#include "glaze/binary/write.hpp" +#include "glaze/beve/read.hpp" +#include "glaze/beve/write.hpp" #include "glaze/glaze.hpp" #include "glaze/json/read.hpp" #include "glaze/json/write.hpp" @@ -36,7 +36,7 @@ namespace glz [[nodiscard]] bool contains(const sv path) noexcept override { - return detail::seek_impl([&](auto&&) {}, user, path); + return seek([&](auto&&) {}, user, path); } bool read(const uint32_t format, const sv path, const sv data) noexcept override @@ -44,12 +44,11 @@ namespace glz error_ctx pe{}; bool success; - if (format == json) { - success = detail::seek_impl([&](auto&& val) { pe = glz::read(val, data); }, user, path); + if (format == JSON) { + success = seek([&](auto&& val) { pe = glz::read(val, data); }, user, path); } else { - success = - detail::seek_impl([&](auto&& val) { pe = glz::read(val, data); }, user, path); + success = seek([&](auto&& val) { pe = glz::read(val, data); }, user, path); } if (success) { @@ -64,11 +63,11 @@ namespace glz bool write(const uint32_t format, const sv path, std::string& data) noexcept override { // TODO: Support write errors when seeking - if (format == json) { - return detail::seek_impl([&](auto&& val) { std::ignore = glz::write_json(val, data); }, user, path); + if (format == JSON) { + return seek([&](auto&& val) { std::ignore = glz::write_json(val, data); }, user, path); } else { - return detail::seek_impl([&](auto&& val) { std::ignore = glz::write_binary(val, data); }, user, path); + return seek([&](auto&& val) { std::ignore = glz::write_beve(val, data); }, user, path); } } @@ -106,11 +105,11 @@ namespace glz bool found = false; - detail::seek_impl( + seek( [&](auto&& parent) { using P = std::decay_t; - detail::seek_impl( + seek( [&](auto&& val) { using V = std::decay_t; if constexpr (std::is_member_function_pointer_v) { @@ -174,7 +173,7 @@ namespace glz decltype(auto) unwrap(T&& val) { using V = std::decay_t; - if constexpr (detail::nullable_t) { + if constexpr (nullable_t) { if (val) { return unwrap(*val); } @@ -197,7 +196,7 @@ namespace glz glz::hash_t type_hash{}; - const auto success = detail::seek_impl( + const auto success = seek( [&](auto&& val) { using V = std::decay_t; if constexpr (std::is_member_function_pointer_v) { @@ -231,11 +230,11 @@ namespace glz const auto parent_ptr = p.first; const auto last_ptr = p.second; - detail::seek_impl( + seek( [&](auto&& parent) { using P = std::decay_t; - detail::seek_impl( + seek( [&](auto&& val) { using V = std::decay_t; if constexpr (std::is_member_function_pointer_v) { @@ -303,7 +302,7 @@ namespace glz using T = std::tuple; constexpr auto N = sizeof...(Args); - for_each([&](auto I) { + for_each([&]() { using V = glz::tuple_element_t; ptr->emplace(name_v, make_api); }); diff --git a/deps/saucer/include/glaze/api/lib.hpp b/deps/saucer/include/glaze/api/lib.hpp index b966ad8..b783957 100644 --- a/deps/saucer/include/glaze/api/lib.hpp +++ b/deps/saucer/include/glaze/api/lib.hpp @@ -45,7 +45,7 @@ namespace glz struct lib_loader final { - using create = glz::iface_fn (*)(void); + using create = glz::iface_fn (*)(void) noexcept; iface api_map{}; std::vector loaded_libs{}; diff --git a/deps/saucer/include/glaze/api/trait.hpp b/deps/saucer/include/glaze/api/trait.hpp index f766414..8cd1da1 100644 --- a/deps/saucer/include/glaze/api/trait.hpp +++ b/deps/saucer/include/glaze/api/trait.hpp @@ -8,6 +8,7 @@ #include "glaze/api/hash.hpp" #include "glaze/core/common.hpp" #include "glaze/core/meta.hpp" +#include "glaze/core/reflect.hpp" #include "glaze/util/string_literal.hpp" namespace glz @@ -21,9 +22,9 @@ namespace glz static constexpr sv type_size_hash = hash128_v>; // must hash for consistent length - static constexpr sv major_version = hash128_i_v[0]>; // must hash for consistent length - static constexpr sv minor_version = hash128_i_v[1]>; // must hash for consistent length - static constexpr sv revision = hash128_i_v[2]>; // must hash for consistent length + static constexpr sv major_version = hash128_i_v.major>; // must hash for consistent length + static constexpr sv minor_version = hash128_i_v.minor>; // must hash for consistent length + static constexpr sv revision = hash128_i_v.patch>; // must hash for consistent length #define std_trait(x) static constexpr sv x = to_sv>() std_trait(is_trivial); @@ -50,8 +51,6 @@ namespace glz std_trait(is_aggregate); #undef std_trait - // static constexpr sv cplusplus = empty_if>(to_sv<__cplusplus>()); - #ifdef __clang__ static constexpr sv clang = "clang"; #endif @@ -64,7 +63,14 @@ namespace glz static constexpr sv blank = ""; // to end possible macros - static constexpr sv members = glz::name_v>; + static constexpr sv members = [] { + if constexpr (glaze_object_t || reflectable) { + return glz::name_v>; + } + else { + return ""; + } + }(); static constexpr sv to_hash = join_v; - static constexpr version_t version = ::glz::version; + static constexpr version_t version = ::glz::version_v; static constexpr sv hash = hash128_v; }; diff --git a/deps/saucer/include/glaze/api/tuplet.hpp b/deps/saucer/include/glaze/api/tuplet.hpp index 8c798a2..4f6d37f 100644 --- a/deps/saucer/include/glaze/api/tuplet.hpp +++ b/deps/saucer/include/glaze/api/tuplet.hpp @@ -9,10 +9,10 @@ namespace glz { template - struct meta> + struct meta> { static constexpr std::string_view name = [](std::index_sequence) { - return join_v, + return join_v, ((I != sizeof...(T) - 1) ? join_v, chars<",">> : join_v>)..., chars<">">>; }(std::make_index_sequence{}); }; diff --git a/deps/saucer/include/glaze/base64/base64.hpp b/deps/saucer/include/glaze/base64/base64.hpp new file mode 100644 index 0000000..e707b7f --- /dev/null +++ b/deps/saucer/include/glaze/base64/base64.hpp @@ -0,0 +1,65 @@ +// Glaze Library +// For the license information refer to glaze.hpp + +#pragma once + +#include +#include +#include +#include + +namespace glz +{ + inline constexpr std::string_view base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + inline std::string read_base64(const std::string_view input) + { + std::string decoded_data; + static constexpr std::array decode_table = [] { + std::array t; + t.fill(-1); + for (int i = 0; i < 64; ++i) { + t[base64_chars[i]] = i; + } + return t; + }(); + + int val = 0, valb = -8; + for (unsigned char c : input) { + if (decode_table[c] == -1) break; // Stop decoding at padding '=' or invalid characters + val = (val << 6) + decode_table[c]; + valb += 6; + if (valb >= 0) { + decoded_data.push_back((val >> valb) & 0xFF); + valb -= 8; + } + } + + return decoded_data; + } + + inline std::string write_base64(const std::string_view input) + { + std::string encoded_data; + + int val = 0, valb = -6; + for (unsigned char c : input) { + val = (val << 8) + c; + valb += 8; + while (valb >= 0) { + encoded_data.push_back(base64_chars[(val >> valb) & 0x3F]); + valb -= 6; + } + } + if (valb > -6) { + encoded_data.push_back(base64_chars[((val << 8) >> (valb + 8)) & 0x3F]); + } + while (encoded_data.size() % 4) { + encoded_data.push_back('='); + } + return encoded_data; + } +} diff --git a/deps/saucer/include/glaze/beve.hpp b/deps/saucer/include/glaze/beve.hpp new file mode 100644 index 0000000..1b8d063 --- /dev/null +++ b/deps/saucer/include/glaze/beve.hpp @@ -0,0 +1,11 @@ +// Glaze Library +// For the license information refer to glaze.hpp + +#pragma once + +#include "glaze/beve/header.hpp" +#include "glaze/beve/ptr.hpp" +#include "glaze/beve/read.hpp" +#include "glaze/beve/wrappers.hpp" +#include "glaze/beve/write.hpp" +#include "glaze/thread/atomic.hpp" diff --git a/deps/saucer/include/glaze/binary/beve_to_json.hpp b/deps/saucer/include/glaze/beve/beve_to_json.hpp similarity index 68% rename from deps/saucer/include/glaze/binary/beve_to_json.hpp rename to deps/saucer/include/glaze/beve/beve_to_json.hpp index 79f0326..22f571d 100644 --- a/deps/saucer/include/glaze/binary/beve_to_json.hpp +++ b/deps/saucer/include/glaze/beve/beve_to_json.hpp @@ -3,22 +3,26 @@ #pragma once -#include "glaze/binary/header.hpp" +#include "glaze/beve/header.hpp" #include "glaze/json/write.hpp" namespace glz { namespace detail { - template - inline void beve_to_json_number(auto&& tag, auto&& ctx, auto&& it, auto&&, auto& out, auto&& ix) noexcept + template + inline void beve_to_json_number(auto&& tag, auto&& ctx, auto&& it, auto&& end, auto& out, auto&& ix) noexcept { const auto number_type = (tag & 0b000'11'000) >> 3; - const uint8_t byte_count = detail::byte_count_lookup[tag >> 5]; + const uint8_t byte_count = byte_count_lookup[tag >> 5]; auto write_number = [&](T&& value) { + if ((it + sizeof(T)) > end) [[unlikely]] { + ctx.error = error_code::syntax_error; + return; + } std::memcpy(&value, it, sizeof(T)); - to_json::template op(value, ctx, out, ix); + to::template op(value, ctx, out, ix); it += sizeof(T); }; @@ -100,9 +104,20 @@ namespace glz } } - template - inline void beve_to_json_value(auto&& ctx, auto&& it, auto&& end, Buffer& out, auto&& ix) noexcept + template + inline void beve_to_json_value(auto&& ctx, auto&& it, auto&& end, Buffer& out, auto&& ix, + uint32_t recursive_depth) { + // Check recursion depth limit + if (recursive_depth >= max_recursive_depth_limit) [[unlikely]] { + ctx.error = error_code::exceeded_max_recursive_depth; + return; + } + + if (it >= end) [[unlikely]] { + ctx.error = error_code::syntax_error; + return; + } const auto tag = uint8_t(*it); const auto type = tag & 0b00000'111; switch (type) { @@ -129,9 +144,16 @@ namespace glz } case tag::string: { ++it; - const auto n = detail::int_from_compressed(ctx, it, end); + const auto n = int_from_compressed(ctx, it, end); + if (bool(ctx.error)) [[unlikely]] { + return; + } + if (uint64_t(end - it) < n) [[unlikely]] { + ctx.error = error_code::unexpected_end; + return; + } const sv value{reinterpret_cast(it), n}; - to_json::template op(value, ctx, out, ix); + to::template op(value, ctx, out, ix); it += n; break; } @@ -144,17 +166,30 @@ namespace glz dump<'\n'>(out, ix); dumpn(ctx.indentation_level, out, ix); } + else { + ++ctx.indentation_level; + } const auto key_type = (tag & 0b000'11'000) >> 3; switch (key_type) { case 0: { // string key - const auto n_fields = detail::int_from_compressed(ctx, it, end); + const auto n_fields = int_from_compressed(ctx, it, end); + if (bool(ctx.error)) { + return; + } for (size_t i = 0; i < n_fields; ++i) { // convert the key - const auto n = detail::int_from_compressed(ctx, it, end); + const auto n = int_from_compressed(ctx, it, end); + if (bool(ctx.error)) [[unlikely]] { + return; + } + if (uint64_t(end - it) < n) [[unlikely]] { + ctx.error = error_code::unexpected_end; + return; + } const sv key{reinterpret_cast(it), n}; - to_json::template op(key, ctx, out, ix); + to::template op(key, ctx, out, ix); if constexpr (Opts.prettify) { dump<": ">(out, ix); } @@ -162,8 +197,46 @@ namespace glz dump<':'>(out, ix); } it += n; - // convert the value - beve_to_json_value(ctx, it, end, out, ix); + beve_to_json_value(ctx, it, end, out, ix, recursive_depth + 1); + if (bool(ctx.error)) [[unlikely]] { + return; + } + if (i != n_fields - 1) { + dump<','>(out, ix); + if constexpr (Opts.prettify) { + dump<'\n'>(out, ix); + dumpn(ctx.indentation_level, out, ix); + } + } + } + break; + } + case 1: + [[fallthrough]]; // signed integer key + case 2: { + // unsigned integer key + const auto n_fields = int_from_compressed(ctx, it, end); + if (bool(ctx.error)) { + return; + } + for (size_t i = 0; i < n_fields; ++i) { + // convert the key + dump<'"'>(out, ix); + beve_to_json_number(tag, ctx, it, end, out, ix); + if (bool(ctx.error)) [[unlikely]] { + return; + } + dump<'"'>(out, ix); + if constexpr (Opts.prettify) { + dump<": ">(out, ix); + } + else { + dump<':'>(out, ix); + } + beve_to_json_value(ctx, it, end, out, ix, recursive_depth + 1); + if (bool(ctx.error)) [[unlikely]] { + return; + } if (i != n_fields - 1) { dump<','>(out, ix); if constexpr (Opts.prettify) { @@ -185,19 +258,29 @@ namespace glz dump<'\n'>(out, ix); dumpn(ctx.indentation_level, out, ix); } + else { + --ctx.indentation_level; + } dump<'}'>(out, ix); break; } case tag::typed_array: { ++it; const auto value_type = (tag & 0b000'11'000) >> 3; - const uint8_t byte_count = detail::byte_count_lookup[tag >> 5]; + const uint8_t byte_count = byte_count_lookup[tag >> 5]; auto write_array = [&](T&& value) { const auto n = int_from_compressed(ctx, it, end); + if (bool(ctx.error)) [[unlikely]] { + return; + } for (size_t i = 0; i < n; ++i) { + if ((it + sizeof(T)) > end) [[unlikely]] { + ctx.error = error_code::unexpected_end; + return; + } std::memcpy(&value, it, sizeof(T)); - to_json::template op(value, ctx, out, ix); + to::template op(value, ctx, out, ix); it += sizeof(T); if (i != n - 1) { dump<','>(out, ix); @@ -291,10 +374,20 @@ namespace glz case 1: { // array of strings const auto n_strings = int_from_compressed(ctx, it, end); + if (bool(ctx.error)) [[unlikely]] { + return; + } for (size_t i = 0; i < n_strings; ++i) { - const auto n = detail::int_from_compressed(ctx, it, end); + const auto n = int_from_compressed(ctx, it, end); + if (bool(ctx.error)) [[unlikely]] { + return; + } + if (uint64_t(end - it) < n) [[unlikely]] { + ctx.error = error_code::unexpected_end; + return; + } const sv value{reinterpret_cast(it), n}; - to_json::template op(value, ctx, out, ix); + to::template op(value, ctx, out, ix); it += n; if (i != n_strings - 1) { dump<','>(out, ix); @@ -322,9 +415,15 @@ namespace glz case tag::generic_array: { ++it; const auto n = int_from_compressed(ctx, it, end); + if (bool(ctx.error)) [[unlikely]] { + return; + } dump<'['>(out, ix); for (size_t i = 0; i < n; ++i) { - beve_to_json_value(ctx, it, end, out, ix); + beve_to_json_value(ctx, it, end, out, ix, recursive_depth + 1); + if (bool(ctx.error)) [[unlikely]] { + return; + } if (i != n - 1) { dump<','>(out, ix); } @@ -347,54 +446,19 @@ namespace glz skip_compressed_int(ctx, it, end); if (bool(ctx.error)) return; - // IMPORTANT: Code was commented because variants should typically write out the JSON value directly - // This makes sense for auto-deducible values, which should be the default behavior. - // In the future we may want a compile time option that dumps the index for cases that cannot be - // auto-deduced - /*const auto index = int_from_compressed(ctx, it, end); - - dump<'{'>(out, ix); - if constexpr (Opts.prettify) { - ctx.indentation_level += Opts.indentation_width; - dump<'\n'>(out, ix); - dumpn(ctx.indentation_level, out, ix); - } - - if constexpr (Opts.prettify) { - dump(out, ix); - } - else { - dump(out, ix); - } - - to_json>::template op(index, ctx, out, ix); - - dump<','>(out, ix); - if constexpr (Opts.prettify) { - dump<'\n'>(out, ix); - dumpn(ctx.indentation_level, out, ix); - } - - if constexpr (Opts.prettify) { - dump(out, ix); - } - else { - dump(out, ix); - }*/ - - beve_to_json_value(ctx, it, end, out, ix); - - /*if constexpr (Opts.prettify) { - ctx.indentation_level -= Opts.indentation_width; - dump<'\n'>(out, ix); - dumpn(ctx.indentation_level, out, ix); + beve_to_json_value(ctx, it, end, out, ix, recursive_depth + 1); + if (bool(ctx.error)) [[unlikely]] { + return; } - dump<'}'>(out, ix);*/ break; } case 2: { // matrices ++it; + if (it >= end) [[unlikely]] { + ctx.error = error_code::syntax_error; + return; + } const auto matrix_header = uint8_t(*it); ++it; @@ -404,6 +468,9 @@ namespace glz dump<'\n'>(out, ix); dumpn(ctx.indentation_level, out, ix); } + else { + ++ctx.indentation_level; + } if constexpr (Opts.prettify) { dump(out, ix); @@ -428,7 +495,10 @@ namespace glz dump(out, ix); } - beve_to_json_value(ctx, it, end, out, ix); + beve_to_json_value(ctx, it, end, out, ix, recursive_depth + 1); + if (bool(ctx.error)) [[unlikely]] { + return; + } dump<','>(out, ix); if constexpr (Opts.prettify) { @@ -443,19 +513,29 @@ namespace glz dump(out, ix); } - beve_to_json_value(ctx, it, end, out, ix); + beve_to_json_value(ctx, it, end, out, ix, recursive_depth + 1); + if (bool(ctx.error)) [[unlikely]] { + return; + } if constexpr (Opts.prettify) { ctx.indentation_level -= Opts.indentation_width; dump<'\n'>(out, ix); dumpn(ctx.indentation_level, out, ix); } + else { + --ctx.indentation_level; + } dump<'}'>(out, ix); break; } case 3: { // complex numbers ++it; + if (it >= end) [[unlikely]] { + ctx.error = error_code::syntax_error; + return; + } const auto complex_header = uint8_t(*it); ++it; @@ -464,12 +544,21 @@ namespace glz // complex array const auto number_tag = complex_header & 0b111'00000; const auto n = int_from_compressed(ctx, it, end); + if (bool(ctx.error)) [[unlikely]] { + return; + } dump<'['>(out, ix); for (size_t i = 0; i < n; ++i) { dump<'['>(out, ix); beve_to_json_number(number_tag, ctx, it, end, out, ix); + if (bool(ctx.error)) [[unlikely]] { + return; + } dump<','>(out, ix); beve_to_json_number(number_tag, ctx, it, end, out, ix); + if (bool(ctx.error)) [[unlikely]] { + return; + } dump<']'>(out, ix); if (i != n - 1) { dump<','>(out, ix); @@ -482,8 +571,14 @@ namespace glz const auto number_tag = complex_header & 0b111'00000; dump<'['>(out, ix); beve_to_json_number(number_tag, ctx, it, end, out, ix); + if (bool(ctx.error)) [[unlikely]] { + return; + } dump<','>(out, ix); beve_to_json_number(number_tag, ctx, it, end, out, ix); + if (bool(ctx.error)) [[unlikely]] { + return; + } dump<']'>(out, ix); } @@ -504,8 +599,8 @@ namespace glz } } - template - [[nodiscard]] inline error_ctx beve_to_json(const BEVEBuffer& beve, JSONBuffer& out) noexcept + template + [[nodiscard]] inline error_ctx beve_to_json(const BEVEBuffer& beve, JSONBuffer& out) { size_t ix{}; // write index @@ -515,7 +610,7 @@ namespace glz context ctx{}; while (it < end) { - detail::beve_to_json_value(ctx, it, end, out, ix); + detail::beve_to_json_value(ctx, it, end, out, ix, 0); if (bool(ctx.error)) { return {ctx.error}; } diff --git a/deps/saucer/include/glaze/binary/header.hpp b/deps/saucer/include/glaze/beve/header.hpp similarity index 68% rename from deps/saucer/include/glaze/binary/header.hpp rename to deps/saucer/include/glaze/beve/header.hpp index 3958683..d99a877 100644 --- a/deps/saucer/include/glaze/binary/header.hpp +++ b/deps/saucer/include/glaze/beve/header.hpp @@ -13,6 +13,20 @@ #include "glaze/core/context.hpp" #include "glaze/util/inline.hpp" +namespace glz +{ + GLZ_ALWAYS_INLINE bool invalid_end(is_context auto& ctx, auto&& it, auto&& end) noexcept + { + if (it >= end) [[unlikely]] { + ctx.error = error_code::unexpected_end; + return true; + } + else [[likely]] { + return false; + } + } +} + namespace glz::tag { constexpr uint8_t null = 0; @@ -46,16 +60,20 @@ namespace glz::tag constexpr uint8_t f128 = 0b100'00'001; } -namespace glz::detail +namespace glz { template constexpr uint8_t byte_count = uint8_t(std::bit_width(sizeof(T)) - 1); - constexpr std::array byte_count_lookup{1, 2, 4, 8, 16, 32, 64, 128}; + inline constexpr std::array byte_count_lookup{1, 2, 4, 8, 16, 32, 64, 128}; - [[nodiscard]] GLZ_ALWAYS_INLINE constexpr size_t int_from_compressed(is_context auto&& ctx, auto&& it, - auto&& end) noexcept + [[nodiscard]] GLZ_ALWAYS_INLINE constexpr size_t int_from_compressed(auto&& ctx, auto&& it, auto&& end) noexcept { + if (it >= end) [[unlikely]] { + ctx.error = error_code::unexpected_end; + return 0; + } + uint8_t header; std::memcpy(&header, it, 1); const uint8_t config = header & 0b000000'11; @@ -82,10 +100,22 @@ namespace glz::detail return h >> 2; } case 3: { - uint64_t h; - std::memcpy(&h, it, 8); - it += 8; - return h >> 2; + // On 32-bit systems it's impossible to address more than 4 GBiB of memory, so we should verify first if we are + // running in 64-bit mode here + if constexpr (sizeof(size_t) > sizeof(uint32_t)) { + uint64_t h; + std::memcpy(&h, it, 8); + it += 8; + h = h >> 2; + static constexpr uint64_t safety_limit = 1ull << 48; // 2^48 + if (h > safety_limit) [[unlikely]] { + ctx.error = error_code::unexpected_end; + return 0; + } + return h; + } + // Fallthrough in case we are in 32-bit mode + [[fallthrough]]; } default: return 0; @@ -94,6 +124,10 @@ namespace glz::detail GLZ_ALWAYS_INLINE constexpr void skip_compressed_int(is_context auto&& ctx, auto&& it, auto&& end) noexcept { + if (invalid_end(ctx, it, end)) { + return; + } + uint8_t header; std::memcpy(&header, it, 1); const uint8_t config = header & 0b000000'11; diff --git a/deps/saucer/include/glaze/binary/ptr.hpp b/deps/saucer/include/glaze/beve/ptr.hpp similarity index 58% rename from deps/saucer/include/glaze/binary/ptr.hpp rename to deps/saucer/include/glaze/beve/ptr.hpp index 3699d2b..6b27180 100644 --- a/deps/saucer/include/glaze/binary/ptr.hpp +++ b/deps/saucer/include/glaze/beve/ptr.hpp @@ -3,8 +3,8 @@ #pragma once -#include "glaze/binary/read.hpp" -#include "glaze/binary/write.hpp" +#include "glaze/beve/read.hpp" +#include "glaze/beve/write.hpp" #include "glaze/core/ptr.hpp" namespace glz @@ -12,12 +12,12 @@ namespace glz template bool read_as_binary(T&& root_value, const sv json_ptr, B&& buffer) { - return read_as(std::forward(root_value), json_ptr, buffer); + return read_as(std::forward(root_value), json_ptr, buffer); } template bool write_as_binary(T&& root_value, const sv json_ptr, B&& buffer) { - return write_as(std::forward(root_value), json_ptr, buffer); + return write_as(std::forward(root_value), json_ptr, buffer); } } diff --git a/deps/saucer/include/glaze/beve/read.hpp b/deps/saucer/include/glaze/beve/read.hpp new file mode 100644 index 0000000..2e36a7f --- /dev/null +++ b/deps/saucer/include/glaze/beve/read.hpp @@ -0,0 +1,1594 @@ +// Glaze Library +// For the license information refer to glaze.hpp + +#pragma once + +#include "glaze/beve/header.hpp" +#include "glaze/beve/skip.hpp" +#include "glaze/core/opts.hpp" +#include "glaze/core/read.hpp" +#include "glaze/core/reflect.hpp" +#include "glaze/file/file_ops.hpp" +#include "glaze/util/dump.hpp" + +// To handle invalid inputs we must check if (it >= end) at the beginning of each function +// This way we can always call a function after incrementing the iterator without needed to do a tail check +// If we know the first function called has an end check, we don't need a guard at the top of the function +// Also, after almost every function call we need to check if an error was produced + +namespace glz +{ + template <> + struct parse + { + template + requires(check_no_header(Opts)) + GLZ_ALWAYS_INLINE static void op(T&& value, Tag&& tag, Ctx&& ctx, It0&& it, It1&& end) + { + if constexpr (const_value_v) { + if constexpr (Opts.error_on_const_read) { + ctx.error = error_code::attempt_const_read; + } + else { + // do not read anything into the const value + skip_value::op(std::forward(ctx), std::forward(it), std::forward(end)); + } + } + else { + using V = std::remove_cvref_t; + from::template op(std::forward(value), std::forward(tag), std::forward(ctx), + std::forward(it), std::forward(end)); + } + } + + template + requires(not check_no_header(Opts)) + GLZ_ALWAYS_INLINE static void op(T&& value, Ctx&& ctx, It0&& it, It1&& end) + { + if constexpr (const_value_v) { + if constexpr (Opts.error_on_const_read) { + ctx.error = error_code::attempt_const_read; + } + else { + // do not read anything into the const value + skip_value::op(std::forward(ctx), std::forward(it), std::forward(end)); + } + } + else { + using V = std::remove_cvref_t; + from::template op(std::forward(value), std::forward(ctx), std::forward(it), + std::forward(end)); + } + } + }; + + template + requires(glaze_value_t && !custom_read) + struct from + { + template + GLZ_ALWAYS_INLINE static void op(Value&& value, Ctx&& ctx, It0&& it, It1&& end) + { + using V = std::decay_t(), meta_wrapper_v))>; + from::template op(get_member(std::forward(value), meta_wrapper_v), + std::forward(ctx), std::forward(it), std::forward(end)); + } + }; + + template + struct from + { + template + GLZ_ALWAYS_INLINE static void op(auto&&, is_context auto&& ctx, auto&& it, auto&& end) noexcept + { + if (invalid_end(ctx, it, end)) { + return; + } + if (uint8_t(*it)) [[unlikely]] { + ctx.error = error_code::syntax_error; + return; + } + ++it; + } + }; + + template <> + struct from