Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements issue 1491 (check for unique keys) #1541

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,17 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> double y = doc["y"]; // The cursor is now after the 2 (at })
> double x = doc["x"]; // Success: [] loops back around to find "x"
> ```
>
> By default, the simdjson does not check that keys are unique. If you are concerned
> about repeated keys, you may use the `find_unique_field` method instead.
> ```c++
> ondemand::parser parser;
> auto json = R"( { "x": 1, "y": 2, "y": 3 } )"_padded;
> auto doc = parser.iterate(json);
> double x = doc.find_unique_field["x"]; // return 2
> double y = doc.find_unique_field["y"]; // will throw with NON_UNIQUE_FIELD error
> ```
> Users should be aware that `find_unique_field` could be significantly less performant.
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. This will
step through each value in the JSON array.

Expand Down
1 change: 1 addition & 0 deletions include/simdjson/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ enum error_code {
PARSER_IN_USE, ///< parser is already in use.
OUT_OF_ORDER_ITERATION, ///< tried to iterate an array or object out of order
INSUFFICIENT_PADDING, ///< The JSON doesn't have enough padding for simdjson to safely parse it.
NON_UNIQUE_FIELD, ///< repeated key in JSON object
NUM_ERROR_CODES
};

Expand Down
14 changes: 14 additions & 0 deletions include/simdjson/generic/ondemand/document-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ simdjson_really_inline simdjson_result<value> document::find_field(std::string_v
simdjson_really_inline simdjson_result<value> document::find_field(const char *key) & noexcept {
return resume_value().find_field(key);
}
simdjson_really_inline simdjson_result<value> document::find_unique_field(std::string_view key) & noexcept {
return resume_value().find_unique_field(key);
}
simdjson_really_inline simdjson_result<value> document::find_unique_field(const char *key) & noexcept {
return resume_value().find_unique_field(key);
}
simdjson_really_inline simdjson_result<value> document::find_field_unordered(std::string_view key) & noexcept {
return resume_value().find_field_unordered(key);
}
Expand Down Expand Up @@ -150,6 +156,14 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::array_iterator> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::end() & noexcept {
return {};
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::find_unique_field(std::string_view key) & noexcept {
if (error()) { return error(); }
return first.find_unique_field(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::find_unique_field(const char *key) & noexcept {
if (error()) { return error(); }
return first.find_unique_field(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document>::find_field_unordered(std::string_view key) & noexcept {
if (error()) { return error(); }
return first.find_field_unordered(key);
Expand Down
12 changes: 12 additions & 0 deletions include/simdjson/generic/ondemand/document.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ class document {
/** @overload simdjson_really_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_field(const char *key) & noexcept;

/**
* Look up a field by name on an object. This function is similar to find_field_unordered but
* returns a NON_UNIQUE_FIELD if the key appears more than once.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object, or NON_UNIQUE_FIELD if the key appears more than once.
*/
simdjson_really_inline simdjson_result<value> find_unique_field(std::string_view key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_unique_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_unique_field(const char *key) & noexcept;
/**
* Look up a field by name on an object, without regard to key order.
*
Expand Down Expand Up @@ -369,6 +379,8 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::document> : public SIM
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](const char *key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_unique_field(std::string_view key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_unique_field(const char *key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(const char *key) & noexcept;

Expand Down
21 changes: 20 additions & 1 deletion include/simdjson/generic/ondemand/object-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,18 @@ simdjson_really_inline simdjson_result<value> object::find_field(const std::stri
if (!has_value) { return NO_SUCH_FIELD; }
return value(iter.child());
}

simdjson_really_inline simdjson_result<value> object::find_unique_field(const std::string_view key) & noexcept {
bool has_value;
SIMDJSON_TRY( iter.find_unique_field_raw(key).get(has_value) );
if (!has_value) { return NO_SUCH_FIELD; }
return value(iter.child());
}
simdjson_really_inline simdjson_result<value> object::find_unique_field(const std::string_view key) && noexcept {
bool has_value;
SIMDJSON_TRY( iter.find_unique_field_raw(key).get(has_value) );
if (!has_value) { return NO_SUCH_FIELD; }
return value(iter.child());
}
simdjson_really_inline simdjson_result<object> object::start(value_iterator &iter) noexcept {
// We don't need to know if the object is empty to start iteration, but we do want to know if there
// is an error--thus `simdjson_unused`.
Expand Down Expand Up @@ -111,5 +122,13 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_field(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_unique_field(std::string_view key) & noexcept {
if (error()) { return error(); }
return first.find_unique_field(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object>::find_unique_field(std::string_view key) && noexcept {
if (error()) { return error(); }
return std::forward<SIMDJSON_IMPLEMENTATION::ondemand::object>(first).find_unique_field(key);
}

} // namespace simdjson
14 changes: 12 additions & 2 deletions include/simdjson/generic/ondemand/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ class object {
simdjson_really_inline simdjson_result<value> find_field(std::string_view key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_field(std::string_view key) && noexcept;
/**
* Look up a field by name on an object. This function is similar to find_field_unordered but
* returns a NON_UNIQUE_FIELD if the key appears more than once.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object, or NON_UNIQUE_FIELD if the key appears more than once.
*/
simdjson_really_inline simdjson_result<value> find_unique_field(std::string_view key) & noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_unique_field(std::string_view key) & noexcept; */
simdjson_really_inline simdjson_result<value> find_unique_field(std::string_view key) && noexcept;

/**
* Look up a field by name on an object, without regard to key order.
Expand Down Expand Up @@ -82,8 +92,6 @@ class object {
static simdjson_really_inline object resume(const value_iterator &iter) noexcept;
simdjson_really_inline object(const value_iterator &iter) noexcept;

simdjson_warn_unused simdjson_really_inline error_code find_field_raw(const std::string_view key) noexcept;

value_iterator iter{};

friend class value;
Expand All @@ -108,6 +116,8 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object> : public SIMDJ
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::object_iterator> end() noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) && noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_unique_field(std::string_view key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_unique_field(std::string_view key) && noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) & noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field_unordered(std::string_view key) && noexcept;
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> operator[](std::string_view key) & noexcept;
Expand Down
16 changes: 15 additions & 1 deletion include/simdjson/generic/ondemand/value-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,12 @@ simdjson_really_inline simdjson_result<value> value::find_field(std::string_view
simdjson_really_inline simdjson_result<value> value::find_field(const char *key) noexcept {
return start_or_resume_object().find_field(key);
}

simdjson_really_inline simdjson_result<value> value::find_unique_field(std::string_view key) noexcept {
return start_or_resume_object().find_unique_field(key);
}
simdjson_really_inline simdjson_result<value> value::find_unique_field(const char *key) noexcept {
return start_or_resume_object().find_unique_field(key);
}
simdjson_really_inline simdjson_result<value> value::find_field_unordered(std::string_view key) noexcept {
return start_or_resume_object().find_field_unordered(key);
}
Expand Down Expand Up @@ -164,6 +169,15 @@ simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>
return first.find_field(key);
}

simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_unique_field(std::string_view key) noexcept {
if (error()) { return error(); }
return first.find_unique_field(key);
}
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_unique_field(const char *key) noexcept {
if (error()) { return error(); }
return first.find_unique_field(key);
}

simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value>::find_field_unordered(std::string_view key) noexcept {
if (error()) { return error(); }
return first.find_field_unordered(key);
Expand Down
20 changes: 20 additions & 0 deletions include/simdjson/generic/ondemand/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ class value {
simdjson_really_inline simdjson_result<value> find_field(std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<value> find_field(const char *key) noexcept;
/**
* Look up a field by name on an object. This function is similar to find_field_unordered but
* returns a NON_UNIQUE_FIELD if the key appears more than once.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object, or NON_UNIQUE_FIELD if the key appears more than once.
*/
simdjson_really_inline simdjson_result<value> find_unique_field(std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<value> find_unique_field(const char *key) noexcept;

/**
* Look up a field by name on an object, without regard to key order.
Expand Down Expand Up @@ -410,6 +420,16 @@ struct simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> : public SIMDJS
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_field(const char *key) noexcept;
/**
* Look up a field by name on an object. This function is similar to find_field_unordered but
* returns a NON_UNIQUE_FIELD if the key appears more than once.
*
* @param key The key to look up.
* @returns The value of the field, or NO_SUCH_FIELD if the field is not in the object, or NON_UNIQUE_FIELD if the key appears more than once.
*/
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_unique_field(std::string_view key) noexcept;
/** @overload simdjson_really_inline simdjson_result<value> find_field(std::string_view key) noexcept; */
simdjson_really_inline simdjson_result<SIMDJSON_IMPLEMENTATION::ondemand::value> find_unique_field(const char *key) noexcept;

/**
* Look up a field by name on an object, without regard to key order.
Expand Down
Loading