diff --git a/include/simdjson/dom/array-inl.h b/include/simdjson/dom/array-inl.h index 0b28dc116..202755248 100644 --- a/include/simdjson/dom/array-inl.h +++ b/include/simdjson/dom/array-inl.h @@ -64,6 +64,10 @@ inline simdjson_result simdjson_result::at(size_t inde return first.at(index); } +inline std::vector& simdjson_result::get_values(std::vector& out) const noexcept { + return first.get_values(out); +} + namespace dom { // @@ -136,20 +140,25 @@ inline simdjson_result array::at_path(std::string_view json_path) const inline simdjson_result> array::at_path_with_wildcard(std::string_view json_path) const noexcept { + + std::vector values; + if (json_path.length() == 3 && json_path[0] == '$' && json_path[1] == '.' && json_path[2] == '*') { - return get_values(); + get_values(values); + return values; } if (json_path.length() == 4 && json_path[0] == '$' && json_path[1] == '[' && json_path[2] == '*' && json_path[3] == ']') { - return get_values(); + get_values(values); + return values; } auto result = at_path(json_path); if (result.error()) { - return std::vector{}; + return values; } return std::vector{std::move(result.value())}; @@ -165,16 +174,13 @@ inline simdjson_result array::at(size_t index) const noexcept { return INDEX_OUT_OF_BOUNDS; } -inline simdjson_result> array::get_values() const noexcept { - SIMDJSON_DEVELOPMENT_ASSERT( - tape.usable()); // https://github.com/simdjson/simdjson/issues/1914 - - std::vector result = {}; +inline std::vector& array::get_values(std::vector& out) const noexcept { + out.reserve(this->size()); for (auto element : *this) { - result.emplace_back(element); + out.emplace_back(element); } - return result; + return out; } inline array::operator element() const noexcept { diff --git a/include/simdjson/dom/array.h b/include/simdjson/dom/array.h index 8b71bbf6d..39bdb41fe 100644 --- a/include/simdjson/dom/array.h +++ b/include/simdjson/dom/array.h @@ -109,7 +109,12 @@ public: * - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed */ inline simdjson_result at_pointer(std::string_view json_pointer) const noexcept; + + /** + * Adds support for JSONPath expression with wildcards '*' + */ inline simdjson_result> at_path_with_wildcard(std::string_view json_path) const noexcept; + /** * Get the value associated with the given JSONPath expression. We only support * JSONPath queries that trivially convertible to JSON Pointer queries: key @@ -143,7 +148,12 @@ public: */ inline simdjson_result at(size_t index) const noexcept; - inline simdjson_result> get_values() const noexcept; + /** + * Gets the values of items in an array element + * This function has linear-time complexity: the values are checked one by one. + */ + + inline std::vector& get_values(std::vector& out) const noexcept; /** * Implicitly convert object to element @@ -174,7 +184,7 @@ public: inline simdjson_result> at_path_with_wildcard(std::string_view json_path) const noexcept; inline simdjson_result at_path(std::string_view json_path) const noexcept; inline simdjson_result at(size_t index) const noexcept; - inline simdjson_result> get_values() const noexcept; + inline std::vector& get_values(std::vector& out) const noexcept; #if SIMDJSON_EXCEPTIONS inline dom::array::iterator begin() const noexcept(false); diff --git a/include/simdjson/dom/element-inl.h b/include/simdjson/dom/element-inl.h index 6bb3efad9..c2931f887 100644 --- a/include/simdjson/dom/element-inl.h +++ b/include/simdjson/dom/element-inl.h @@ -407,7 +407,7 @@ inline bool is_pointer_well_formed(std::string_view json_pointer) noexcept { inline bool is_path_well_formed(std::string_view json_path) noexcept { size_t i = 0; // if JSONPath starts with $, skip it - if (!json_path.empty() && json_path.front() == '$') { + if (!json_path.empty() && json_path.starts_with('$')) { i = 1; } diff --git a/include/simdjson/dom/object-inl.h b/include/simdjson/dom/object-inl.h index c89f8959a..84a5678be 100644 --- a/include/simdjson/dom/object-inl.h +++ b/include/simdjson/dom/object-inl.h @@ -50,8 +50,8 @@ inline simdjson_result simdjson_result::at_key(std::s if (error()) { return error(); } return first.at_key(key); } -inline std::vector simdjson_result::get_values() const noexcept { - return first.get_values(); +inline std::vector& simdjson_result::get_values(std::vector& out) const noexcept { + return first.get_values(out); } inline simdjson_result simdjson_result::at_key_case_insensitive(std::string_view key) const noexcept { if (error()) { return error(); } @@ -157,12 +157,8 @@ inline simdjson_result> process_elements_recursive(std::vec return accumulator; } - std::string child_result_key = "$"; - child_result_key.reserve(path_suffix.size() + 1); - child_result_key += path_suffix; - std::vector child_result = - current->at_path_with_wildcard(child_result_key).value(); + current->at_path_with_wildcard(path_suffix).value(); accumulator.reserve(accumulator.size() + child_result.size()); accumulator.insert(accumulator.end(), @@ -179,7 +175,7 @@ inline simdjson_result> object::at_path_with_wildcard(std:: size_t i = 0; // if JSONPath starts with $, skip it - if (!json_path.empty() && json_path.front() == '$') { + if (!json_path.empty() && json_path.starts_with('$')) { i = 1; } @@ -190,21 +186,26 @@ inline simdjson_result> object::at_path_with_wildcard(std:: } if (json_path.find("*") != std::string::npos) { + + std::vector child_values; + if (json_path.length() == 4) { - std::string_view match = "$[*]"; + constexpr std::string_view match = "$[*]"; if (memcmp(json_path.data(), match.data(), 4) == 0) { - return get_values(); + get_values(child_values); + return child_values; } } if (json_path.length() == 3) { - std::string_view match = "$.*"; + constexpr std::string_view match = "$.*"; if (memcmp(json_path.data(), match.data(), 3) == 0) { - return get_values(); + get_values(child_values); + return child_values; } } - if (!json_path.empty() && json_path.front() == '$') { + if (!json_path.empty() && json_path.starts_with('$')) { i = 1; } @@ -235,11 +236,10 @@ inline simdjson_result> object::at_path_with_wildcard(std:: } } - std::vector child_values; if (key.size() > 0) { if (key == "*") { - child_values = get_values(); + get_values(child_values); } else { std::string child_key = "/"; child_key.reserve(key.size() + 1); @@ -247,7 +247,8 @@ inline simdjson_result> object::at_path_with_wildcard(std:: child_values.emplace_back(at_pointer(child_key).value()); } - json_path = json_path.substr(i); + std::string new_json_path = "$" + std::string(json_path.substr(i)); + json_path = new_json_path; std::vector result; return process_elements_recursive(child_values.begin(), child_values.end(), json_path, result); @@ -270,17 +271,16 @@ inline simdjson_result object::at_key(std::string_view key) const noexc return NO_SUCH_FIELD; } -inline std::vector object::get_values() const noexcept { +inline std::vector& object::get_values(std::vector& out) const noexcept { iterator end_field = end(); iterator begin_field = begin(); - std::vector result = {}; - result.reserve(std::distance(begin_field, end_field)); + out.reserve(std::distance(begin_field, end_field)); for (iterator field = begin_field; field != end_field; ++field) { - result.emplace_back(field.value()); + out.emplace_back(field.value()); } - return result; + return out; } // In case you wonder why we need this, please see // https://github.com/simdjson/simdjson/issues/323 diff --git a/include/simdjson/dom/object.h b/include/simdjson/dom/object.h index d64dfe783..06750469d 100644 --- a/include/simdjson/dom/object.h +++ b/include/simdjson/dom/object.h @@ -207,7 +207,11 @@ public: */ inline simdjson_result at_key(std::string_view key) const noexcept; - inline std::vector get_values() const noexcept; + /** + * Gets the values associated with keys of an object + * This function has linear-time complexity: the keys are checked one by one. + */ + inline std::vector& get_values(std::vector& out) const noexcept; /** * Get the value associated with the given key in a case-insensitive manner. @@ -270,7 +274,7 @@ public: inline simdjson_result> at_path_with_wildcard(std::string_view json_path_new) const noexcept; inline simdjson_result at_path(std::string_view json_path) const noexcept; inline simdjson_result at_key(std::string_view key) const noexcept; - inline std::vector get_values() const noexcept; + inline std::vector& get_values(std::vector& out) const noexcept; inline simdjson_result at_key_case_insensitive(std::string_view key) const noexcept; #if SIMDJSON_EXCEPTIONS