diff --git a/single_include/nlohmann/json_view.hpp b/single_include/nlohmann/json_view.hpp index 9ba78ae74..0682c08be 100644 --- a/single_include/nlohmann/json_view.hpp +++ b/single_include/nlohmann/json_view.hpp @@ -4340,11 +4340,11 @@ NLOHMANN_JSON_NAMESPACE_END -#include // sort +#include // min, sort #include // array -#include // size_t +#include // offsetof, size_t #include // int64_t, uint8_t, uint16_t, uint32_t, uint64_t -#include // memcmp, memcpy +#include // memcmp, memcpy, memset #include // numeric_limits #include // string #include // vector @@ -4410,10 +4410,11 @@ inline bool float_token_layout(const char* first, const char* last, std::size_t& { return false; } - while (digit(p)) + do { ++p; } + while (digit(p)); dot = std::string::npos; if (p != last && *p == '.') { @@ -4422,10 +4423,11 @@ inline bool float_token_layout(const char* first, const char* last, std::size_t& { return false; } - while (digit(p)) + do { ++p; } + while (digit(p)); } mantissa_end = static_cast(p - first); if (p != last && (*p == 'e' || *p == 'E')) @@ -4436,10 +4438,11 @@ inline bool float_token_layout(const char* first, const char* last, std::size_t& { return false; } - while (digit(p)) + do { ++p; } + while (digit(p)); } return p == last; } @@ -4724,7 +4727,7 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v copy_node(d.nodes); while (!stack.empty()) { - frame& top = stack.back(); + const frame top = stack.back(); if (top.cur == top.end) { node& c = out[top.index]; @@ -4733,20 +4736,14 @@ inline void compact_nodes(const document_data& d, std::size_t arena_size, std::v stack.pop_back(); continue; } - ++top.count; - const node* v = nullptr; if (top.object) { out.push_back(string_node(*top.cur)); - v = document_data::deref(top.cur + 1); - top.cur = document_data::after(top.cur + 1); } - else - { - v = document_data::deref(top.cur); - top.cur = document_data::after(top.cur); - } - copy_node(v); // may grow the stack (top is not used afterwards) + const node* const value = top.cur + (top.object ? 1 : 0); + stack.back().cur = document_data::after(value); + ++stack.back().count; + copy_node(document_data::deref(value)); // may grow the stack } } @@ -4757,17 +4754,15 @@ inline std::vector save_image(const document_data& d) throw_type_error(320, "json_document images need a little-endian target"); // LCOV_EXCL_LINE #endif const std::size_t arena_size = d.arena_size; - const node* nodes = d.nodes; - std::size_t count = d.node_count; std::vector compacted; std::string text_tail; std::string arena_tail; if (d.edits) { compact_nodes(d, arena_size, compacted, text_tail, arena_tail); - nodes = compacted.data(); - count = compacted.size(); } + const node* const nodes = d.edits ? compacted.data() : d.nodes; + const std::size_t count = d.edits ? compacted.size() : d.node_count; const std::size_t text_size = d.size + text_tail.size(); const std::size_t total_arena = arena_size + arena_tail.size(); if (NLOHMANN_VIEW_UNLIKELY(text_size >= image_limit || total_arena >= image_limit || count >= image_limit)) @@ -4787,14 +4782,13 @@ inline std::vector save_image(const document_data& d) std::memcpy(o, &h, sizeof(h)); o += sizeof(h); std::memcpy(o, nodes, count * sizeof(node)); - // the hash indexes are rebuilt by load() + // the hash indexes are rebuilt by load(), whose check rejects any other + // extra of an object, and the same document saves to the same bytes for (std::size_t i = 0; i < count; ++i) { if (nodes[i].kind == static_cast(value_t::object) && nodes[i].extra != 0) { - node n = nodes[i]; - n.extra = 0; - std::memcpy(o + (i * sizeof(node)), &n, sizeof(node)); + std::memset(o + (i * sizeof(node)) + offsetof(node, extra), 0, sizeof(nodes[i].extra)); } } o += count * sizeof(node); @@ -4833,21 +4827,22 @@ inline bool scan_number_token(const unsigned char* s, std::size_t len, number_to const unsigned char* p = s; t.negative = p != e && *p == '-'; p += t.negative ? 1 : 0; - t.int_start = p; if (p == e) { return false; } + t.int_start = p; if (*p == '0') { ++p; } else if (*p >= '1' && *p <= '9') { - while (p != e && is_digit(*p)) + do { ++p; } + while (p != e && is_digit(*p)); } else { @@ -4880,11 +4875,12 @@ inline bool scan_number_token(const unsigned char* s, std::size_t len, number_to { return false; } - while (p != e && is_digit(*p)) + do { t.exponent = t.exponent < 100000 ? (t.exponent * 10) + (*p - '0') : t.exponent; ++p; } + while (p != e && is_digit(*p)); t.exponent = exp_negative ? -t.exponent : t.exponent; t.is_float = true; } @@ -4895,7 +4891,7 @@ inline bool scan_number_token(const unsigned char* s, std::size_t len, number_to /// writes "many" instead; the caller accepts both) inline std::uint16_t float_layout(const number_token& t) { - return static_cast((t.int_digits < 255 ? t.int_digits : 255) | ((t.frac_digits < 255 ? t.frac_digits : 255) << 8u)); + return static_cast((std::min)(t.int_digits, std::size_t{255}) | ((std::min)(t.frac_digits, std::size_t{255}) << 8u)); } /// whether a float token (well-formed, per scan_number_token) is finite as @@ -5297,14 +5293,10 @@ inline void load_image(document_data& d, const std::uint8_t* image, std::size_t // the hash indexes of large objects, as after parsing for (std::size_t i = 0; i < count; ++i) { - node& n = d.nodes[i]; - if (n.kind == static_cast(value_t::object)) + const node& n = d.nodes[i]; + if (n.kind == static_cast(value_t::object) && n.len >= document_data::index_min_members) { - n.extra = 0; - if (n.len >= document_data::index_min_members) - { - d.large_objects.push_back(static_cast(i)); - } + d.large_objects.push_back(static_cast(i)); } } build_object_indexes(d); @@ -7756,7 +7748,7 @@ class basic_json_document return m_data ? m_data->node_count : 0; } - /// bytes held by the document (index, decoded strings, owned text or image) + /// bytes held by the document (index, decoded strings, and owned text or image) std::size_t memory_usage() const noexcept { if (!m_data)