#ifndef SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H #ifndef SIMDJSON_CONDITIONAL_INCLUDE #define SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H #include "simdjson/generic/ondemand/base.h" #include "simdjson/generic/ondemand/json_iterator.h" #include "simdjson/generic/ondemand/deserialize.h" #include "simdjson/generic/ondemand/value.h" #include #endif // SIMDJSON_CONDITIONAL_INCLUDE namespace simdjson { namespace SIMDJSON_IMPLEMENTATION { namespace ondemand { /** * A JSON document. It holds a json_iterator instance. * * Used by tokens to get text, and string buffer location. * * You must keep the document around during iteration. */ class document { public: /** * Create a new invalid document. * * Exists so you can declare a variable and later assign to it before use. */ simdjson_inline document() noexcept = default; simdjson_inline document(const document &other) noexcept = delete; // pass your documents by reference, not by copy simdjson_inline document(document &&other) noexcept = default; simdjson_inline document &operator=(const document &other) noexcept = delete; simdjson_inline document &operator=(document &&other) noexcept = default; /** * Cast this JSON value to an array. * * @returns An object that can be used to iterate the array. * @returns INCORRECT_TYPE If the JSON value is not an array. */ simdjson_inline simdjson_result get_array() & noexcept; /** * Cast this JSON value to an object. * * @returns An object that can be used to look up or iterate fields. * @returns INCORRECT_TYPE If the JSON value is not an object. */ simdjson_inline simdjson_result get_object() & noexcept; /** * Cast this JSON value to an unsigned integer. * * @returns A signed 64-bit integer. * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer. */ simdjson_inline simdjson_result get_uint64() noexcept; /** * Cast this JSON value (inside string) to an unsigned integer. * * @returns A signed 64-bit integer. * @returns INCORRECT_TYPE If the JSON value is not a 64-bit unsigned integer. */ simdjson_inline simdjson_result get_uint64_in_string() noexcept; /** * Cast this JSON value to a signed integer. * * @returns A signed 64-bit integer. * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer. */ simdjson_inline simdjson_result get_int64() noexcept; /** * Cast this JSON value (inside string) to a signed integer. * * @returns A signed 64-bit integer. * @returns INCORRECT_TYPE If the JSON value is not a 64-bit integer. */ simdjson_inline simdjson_result get_int64_in_string() noexcept; /** * Cast this JSON value to a double. * * @returns A double. * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number. */ simdjson_inline simdjson_result get_double() noexcept; /** * Cast this JSON value (inside string) to a double. * * @returns A double. * @returns INCORRECT_TYPE If the JSON value is not a valid floating-point number. */ simdjson_inline simdjson_result get_double_in_string() noexcept; /** * Cast this JSON value to a string. * * The string is guaranteed to be valid UTF-8. * * Important: Calling get_string() twice on the same document is an error. * * @param Whether to allow a replacement character for unmatched surrogate pairs. * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next * time it parses a document or when it is destroyed. * @returns INCORRECT_TYPE if the JSON value is not a string. */ simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; /** * Attempts to fill the provided std::string reference with the parsed value of the current string. * * The string is guaranteed to be valid UTF-8. * * Important: a value should be consumed once. Calling get_string() twice on the same value * is an error. * * Performance: This method may be slower than get_string() or get_string(bool) because it may need to allocate memory. * We recommend you avoid allocating an std::string unless you need to. * * @returns INCORRECT_TYPE if the JSON value is not a string. Otherwise, we return SUCCESS. */ template simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; /** * Cast this JSON value to a string. * * The string is not guaranteed to be valid UTF-8. See https://simonsapin.github.io/wtf-8/ * * Important: Calling get_wobbly_string() twice on the same document is an error. * * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next * time it parses a document or when it is destroyed. * @returns INCORRECT_TYPE if the JSON value is not a string. */ simdjson_inline simdjson_result get_wobbly_string() noexcept; /** * Cast this JSON value to a raw_json_string. * * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n). * * @returns A pointer to the raw JSON for the given string. * @returns INCORRECT_TYPE if the JSON value is not a string. */ simdjson_inline simdjson_result get_raw_json_string() noexcept; /** * Cast this JSON value to a bool. * * @returns A bool value. * @returns INCORRECT_TYPE if the JSON value is not true or false. */ simdjson_inline simdjson_result get_bool() noexcept; /** * Cast this JSON value to a value when the document is an object or an array. * * You must not have begun iterating through the object or array. When * SIMDJSON_DEVELOPMENT_CHECKS is set to 1 (which is the case when building in Debug mode * by default), and you have already begun iterating, * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use * rewind() to reset the document to its initial state before calling this method. * * @returns A value if a JSON array or object cannot be found. * @returns SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function). */ simdjson_inline simdjson_result get_value() noexcept; /** * Checks if this JSON value is null. If and only if the value is * null, then it is consumed (we advance). If we find a token that * begins with 'n' but is not 'null', then an error is returned. * * @returns Whether the value is null. * @returns INCORRECT_TYPE If the JSON value begins with 'n' and is not 'null'. */ simdjson_inline simdjson_result is_null() noexcept; /** * Get this value as the given type. * * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool * * You may use get_double(), get_bool(), get_uint64(), get_int64(), * get_object(), get_array(), get_raw_json_string(), or get_string() instead. * * @returns A value of the given type, parsed from the JSON. * @returns INCORRECT_TYPE If the JSON value is not the given type. */ template simdjson_inline simdjson_result get() & #if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif { static_assert(std::is_default_constructible::value, "Cannot initialize the specified type."); T out{}; SIMDJSON_TRY(get(out)); return out; } /** * @overload template simdjson_result get() & noexcept * * We disallow the use tag_invoke CPO on a moved document; it may create UB * if user uses `ondemand::array` or `ondemand::object` in their custom type. * * The member function is still remains specialize-able for compatibility * reasons, but we completely disallow its use when a tag_invoke customization * is provided. */ template simdjson_inline simdjson_result get() && #if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif { static_assert(!std::is_same::value && !std::is_same::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document being alive; that would be Undefined Behaviour."); return static_cast(*this).get(); } /** * Get this value as the given type. * * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value * * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances. * * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized. * @returns INCORRECT_TYPE If the JSON value is of the given type. * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template simdjson_warn_unused simdjson_inline error_code get(T &out) & #if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif { #if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " "And you do not seem to have added support for it. Indeed, we have that " "simdjson::custom_deserializable is false and the type T is not a default type " "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; } #else // SIMDJSON_SUPPORTS_CONCEPTS // Unless the simdjson library or the user provides an inline implementation, calling this method should // immediately fail. static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." " You may also add support for custom types, see our documentation."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; #endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ template simdjson_deprecated simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS /** * Cast this JSON value to an instance of type T. The programmer is responsible for * providing an implementation of get for the type T, if T is not one of the types * supported by the library (object, array, raw_json_string, string_view, uint64_t, etc.) * * See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#adding-support-for-custom-types * * @returns An instance of type T */ template explicit simdjson_inline operator T() & noexcept(false); template explicit simdjson_deprecated simdjson_inline operator T() && noexcept(false); /** * Cast this JSON value to an array. * * @returns An object that can be used to iterate the array. * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an array. */ simdjson_inline operator array() & noexcept(false); /** * Cast this JSON value to an object. * * @returns An object that can be used to look up or iterate fields. * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not an object. */ simdjson_inline operator object() & noexcept(false); /** * Cast this JSON value to an unsigned integer. * * @returns A signed 64-bit integer. * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit unsigned integer. */ simdjson_inline operator uint64_t() noexcept(false); /** * Cast this JSON value to a signed integer. * * @returns A signed 64-bit integer. * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a 64-bit integer. */ simdjson_inline operator int64_t() noexcept(false); /** * Cast this JSON value to a double. * * @returns A double. * @exception simdjson_error(INCORRECT_TYPE) If the JSON value is not a valid floating-point number. */ simdjson_inline operator double() noexcept(false); /** * Cast this JSON value to a string. * * The string is guaranteed to be valid UTF-8. * * @returns An UTF-8 string. The string is stored in the parser and will be invalidated the next * time it parses a document or when it is destroyed. * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string. */ simdjson_inline operator std::string_view() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a raw_json_string. * * The string is guaranteed to be valid UTF-8, and may have escapes in it (e.g. \\ or \n). * * @returns A pointer to the raw JSON for the given string. * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not a string. */ simdjson_inline operator raw_json_string() noexcept(false) simdjson_lifetime_bound; /** * Cast this JSON value to a bool. * * @returns A bool value. * @exception simdjson_error(INCORRECT_TYPE) if the JSON value is not true or false. */ simdjson_inline operator bool() noexcept(false); /** * Cast this JSON value to a value when the document is an object or an array. * * You must not have begun iterating through the object or array. When * SIMDJSON_DEVELOPMENT_CHECKS is defined, and you have already begun iterating, * you will get an OUT_OF_ORDER_ITERATION error. If you have begun iterating, you can use * rewind() to reset the document to its initial state before calling this method. * * @returns A value value if a JSON array or object cannot be found. * @exception SCALAR_DOCUMENT_AS_VALUE error is the document is a scalar (see is_scalar() function). */ simdjson_inline operator value() noexcept(false); #endif /** * This method scans the array and counts the number of elements. * The count_elements method should always be called before you have begun * iterating through the array: it is expected that you are pointing at * the beginning of the array. * The runtime complexity is linear in the size of the array. After * calling this function, if successful, the array is 'rewinded' at its * beginning as if it had never been accessed. If the JSON is malformed (e.g., * there is a missing comma), then an error is returned and it is no longer * safe to continue. Note that count_elements() does not validate the JSON values, * only the structure of the array. */ simdjson_inline simdjson_result count_elements() & noexcept; /** * This method scans the object and counts the number of key-value pairs. * The count_fields method should always be called before you have begun * iterating through the object: it is expected that you are pointing at * the beginning of the object. * The runtime complexity is linear in the size of the object. After * calling this function, if successful, the object is 'rewinded' at its * beginning as if it had never been accessed. If the JSON is malformed (e.g., * there is a missing comma), then an error is returned and it is no longer * safe to continue. * * To check that an object is empty, it is more performant to use * the is_empty() method. */ simdjson_inline simdjson_result count_fields() & noexcept; /** * Get the value at the given index in the array. This function has linear-time complexity. * This function should only be called once on an array instance since the array iterator is not reset between each call. * * @return The value at the given index, or: * - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length */ simdjson_inline simdjson_result at(size_t index) & noexcept; /** * Begin array iteration. * * Part of the std::iterable interface. */ simdjson_inline simdjson_result begin() & noexcept; /** * Sentinel representing the end of the array. * * Part of the std::iterable interface. */ simdjson_inline simdjson_result end() & noexcept; /** * Look up a field by name on an object (order-sensitive). By order-sensitive, we mean that * fields must be accessed in the order they appear in the JSON text (although you can * skip fields). See find_field_unordered() and operator[] for an order-insensitive version. * * The following code reads z, then y, then x, and thus will not retrieve x or y if fed the * JSON `{ "x": 1, "y": 2, "z": 3 }`: * * ```cpp * simdjson::ondemand::parser parser; * auto obj = parser.parse(R"( { "x": 1, "y": 2, "z": 3 } )"_padded); * double z = obj.find_field("z"); * double y = obj.find_field("y"); * double x = obj.find_field("x"); * ``` * * **Raw Keys:** The lookup will be done against the *raw* key, and will not unescape keys. * e.g. `object["a"]` will match `{ "a": 1 }`, but will *not* match `{ "\u0061": 1 }`. * * * You must consume the fields on an object one at a time. A request for a new key * invalidates previous field values: it makes them unsafe. E.g., the array * given by content["bids"].get_array() should not be accessed after you have called * content["asks"].get_array(). You can detect such mistakes by first compiling and running * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an * OUT_OF_ORDER_ITERATION error is generated. * * You are expected to access keys only once. You should access the value corresponding to * a key a single time. Doing object["mykey"].to_string()and then again object["mykey"].to_string() * is an error. * * @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. */ simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; /** @overload simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; */ simdjson_inline simdjson_result find_field(const char *key) & noexcept; /** * Look up a field by name on an object, without regard to key order. * * **Performance Notes:** This is a bit less performant than find_field(), though its effect varies * and often appears negligible. It starts out normally, starting out at the last field; but if * the field is not found, it scans from the beginning of the object to see if it missed it. That * missing case has a non-cache-friendly bump and lots of extra scanning, especially if the object * in question is large. The fact that the extra code is there also bumps the executable size. * * We default operator[] on find_field_unordered() for convenience. * It is the default because it would be highly surprising (and hard to debug) if the * default behavior failed to look up a field just because it was in the wrong order--and many * APIs assume this. Therefore, you must be explicit if you want to treat objects as out of order. * * Use find_field() if you are sure fields will be in order (or are willing to treat it as if the * field was not there when they are not in order). * * You must consume the fields on an object one at a time. A request for a new key * invalidates previous field values: it makes them unsafe. E.g., the array * given by content["bids"].get_array() should not be accessed after you have called * content["asks"].get_array(). You can detect such mistakes by first compiling and running * the code in Debug mode (or with the macro `SIMDJSON_DEVELOPMENT_CHECKS` set to 1): an * OUT_OF_ORDER_ITERATION error is generated. * * You are expected to access keys only once. You should access the value corresponding to a key * a single time. Doing object["mykey"].to_string() and then again object["mykey"].to_string() * is an error. * * @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. */ simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ simdjson_inline simdjson_result find_field_unordered(const char *key) & noexcept; /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; /** @overload simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; */ simdjson_inline simdjson_result operator[](const char *key) & noexcept; simdjson_result operator[](int) & noexcept = delete; /** * Get the type of this JSON value. It does not validate or consume the value. * E.g., you must still call "is_null()" to check that a value is null even if * "type()" returns json_type::null. * * The answer can be one of * simdjson::ondemand::json_type::object, * simdjson::ondemand::json_type::array, * simdjson::ondemand::json_type::string, * simdjson::ondemand::json_type::number, * simdjson::ondemand::json_type::boolean, * simdjson::ondemand::json_type::null. * * Starting with simdjson 4.0, this function will return simdjson::ondemand::json_type::unknown * given a bad token. * This allows you to identify a case such as {"key": NaN} and identify the NaN value. * The simdjson::ondemand::json_type::unknown value should only happen with non-valid JSON. * * NOTE: If you're only expecting a value to be one type (a typical case), it's generally * better to just call .get_double, .get_string, etc. and check for INCORRECT_TYPE (or just * let it throw an exception). * * Prior to simdjson 4.0, this function would return an error given a bad token. * Starting with simdjson 4.0, it will return simdjson::ondemand::json_type::unknown. * This allows you to identify a case such as {"key": NaN} and identify the NaN value. * The simdjson::ondemand::json_type::unknown value should only happen with non-valid JSON. */ simdjson_inline simdjson_result type() noexcept; /** * Checks whether the document is a scalar (string, number, null, Boolean). * Returns false when there it is an array or object. * * @returns true if the type is string, number, null, Boolean * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". */ simdjson_inline simdjson_result is_scalar() noexcept; /** * Checks whether the document is a string. * * @returns true if the type is string * @error TAPE_ERROR when the JSON value is a bad token like "}" "," or "alse". */ simdjson_inline simdjson_result is_string() noexcept; /** * Checks whether the document is a negative number. * * @returns true if the number if negative. */ simdjson_inline bool is_negative() noexcept; /** * Checks whether the document is an integer number. Note that * this requires to partially parse the number string. If * the value is determined to be an integer, it may still * not parse properly as an integer in subsequent steps * (e.g., it might overflow). * * @returns true if the number if negative. */ simdjson_inline simdjson_result is_integer() noexcept; /** * Determine the number type (integer or floating-point number) as quickly * as possible. This function does not fully validate the input. It is * useful when you only need to classify the numbers, without parsing them. * * If you are planning to retrieve the value or you need full validation, * consider using the get_number() method instead: it will fully parse * and validate the input, and give you access to the type: * get_number().get_number_type(). * * get_number_type() is number_type::unsigned_integer if we have * an integer greater or equal to 9223372036854775808 and no larger than 18446744073709551615. * get_number_type() is number_type::signed_integer if we have an * integer that is less than 9223372036854775808 and greater or equal to -9223372036854775808. * get_number_type() is number_type::big_integer if we have an integer outside * of those ranges (either larger than 18446744073709551615 or smaller than -9223372036854775808). * Otherwise, get_number_type() has value number_type::floating_point_number * * This function requires processing the number string, but it is expected * to be faster than get_number().get_number_type() because it is does not * parse the number value. * * @returns the type of the number */ simdjson_inline simdjson_result get_number_type() noexcept; /** * Attempt to parse an ondemand::number. An ondemand::number may * contain an integer value or a floating-point value, the simdjson * library will autodetect the type. Thus it is a dynamically typed * number. Before accessing the value, you must determine the detected * type. * * number.get_number_type() is number_type::signed_integer if we have * an integer in [-9223372036854775808,9223372036854775808) * You can recover the value by calling number.get_int64() and you * have that number.is_int64() is true. * * number.get_number_type() is number_type::unsigned_integer if we have * an integer in [9223372036854775808,18446744073709551616) * You can recover the value by calling number.get_uint64() and you * have that number.is_uint64() is true. * * Otherwise, number.get_number_type() has value number_type::floating_point_number * and we have a binary64 number. * You can recover the value by calling number.get_double() and you * have that number.is_double() is true. * * You must check the type before accessing the value: it is an error * to call "get_int64()" when number.get_number_type() is not * number_type::signed_integer and when number.is_int64() is false. */ simdjson_warn_unused simdjson_inline simdjson_result get_number() noexcept; /** * Get the raw JSON for this token. * * The string_view will always point into the input buffer. * * The string_view will start at the beginning of the token, and include the entire token * *as well as all spaces until the next token (or EOF).* This means, for example, that a * string token always begins with a " and is always terminated by the final ", possibly * followed by a number of spaces. * * The string_view is *not* null-terminated. If this is a scalar (string, number, * boolean, or null), the character after the end of the string_view may be the padded buffer. * * Tokens include: * - { * - [ * - "a string (possibly with UTF-8 or backslashed characters like \\\")". * - -1.2e-100 * - true * - false * - null */ simdjson_inline simdjson_result raw_json_token() noexcept; /** * Reset the iterator inside the document instance so we are pointing back at the * beginning of the document, as if it had just been created. It invalidates all * values, objects and arrays that you have created so far (including unescaped strings). */ inline void rewind() noexcept; /** * Returns debugging information. */ inline std::string to_debug_string() noexcept; /** * Some unrecoverable error conditions may render the document instance unusable. * The is_alive() method returns true when the document is still suitable. */ inline bool is_alive() noexcept; /** * Returns the current location in the document if in bounds. */ inline simdjson_result current_location() const noexcept; /** * Returns true if this document has been fully parsed. * If you have consumed the whole document and at_end() returns * false, then there may be trailing content. */ inline bool at_end() const noexcept; /** * Returns the current depth in the document if in bounds. * * E.g., * 0 = finished with document * 1 = document root value (could be [ or {, not yet known) * 2 = , or } inside root array/object * 3 = key or value inside root array/object. */ simdjson_inline int32_t current_depth() const noexcept; /** * Get the value associated with the given JSON pointer. We use the RFC 6901 * https://tools.ietf.org/html/rfc6901 standard. * * ondemand::parser parser; * auto json = R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded; * auto doc = parser.iterate(json); * doc.at_pointer("/foo/a/1") == 20 * * It is allowed for a key to be the empty string: * * ondemand::parser parser; * auto json = R"({ "": { "a": [ 10, 20, 30 ] }})"_padded; * auto doc = parser.iterate(json); * doc.at_pointer("//a/1") == 20 * * Key values are matched exactly, without unescaping or Unicode normalization. * We do a byte-by-byte comparison. E.g. * * const padded_string json = "{\"\\u00E9\":123}"_padded; * auto doc = parser.iterate(json); * doc.at_pointer("/\\u00E9") == 123 * doc.at_pointer((const char*)u8"/\u00E9") returns an error (NO_SUCH_FIELD) * * Note that at_pointer() automatically calls rewind between each call. Thus * all values, objects and arrays that you have created so far (including unescaped strings) * are invalidated. After calling at_pointer, you need to consume the result: string values * should be stored in your own variables, arrays should be decoded and stored in your own array-like * structures and so forth. * * Also note that at_pointer() relies on find_field() which implies that we do not unescape keys when matching * * @return The value associated with the given JSON pointer, or: * - NO_SUCH_FIELD if a field does not exist in an object * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length * - INCORRECT_TYPE if a non-integer is used to access an array * - INVALID_JSON_POINTER if the JSON pointer is invalid and cannot be parsed * - SCALAR_DOCUMENT_AS_VALUE if the json_pointer is empty and the document is not a scalar (see is_scalar() function). */ simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; /** * Get the value associated with the given JSONPath expression. We only support * JSONPath queries that trivially convertible to JSON Pointer queries: key * names and array indices. * * https://www.rfc-editor.org/rfc/rfc9535 (RFC 9535) * * Key values are matched exactly, without unescaping or Unicode normalization. * We do a byte-by-byte comparison. E.g. * * const padded_string json = "{\"\\u00E9\":123}"_padded; * auto doc = parser.iterate(json); * doc.at_path(".\\u00E9") == 123 * doc.at_path((const char*)u8".\u00E9") returns an error (NO_SUCH_FIELD) * * @return The value associated with the given JSONPath expression, or: * - INVALID_JSON_POINTER if the JSONPath to JSON Pointer conversion fails * - NO_SUCH_FIELD if a field does not exist in an object * - INDEX_OUT_OF_BOUNDS if an array index is larger than an array length * - INCORRECT_TYPE if a non-integer is used to access an array */ simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; /** * Get all values matching the given JSONPath expression with wildcard support. * * Supports wildcard patterns like "$.array[*]" or "$.object.*" to match multiple elements. * * This method materializes all matching values into a vector. * The document will be consumed after this call. * * @param json_path JSONPath expression with wildcards * @return Vector of values matching the wildcard pattern, or: * - INVALID_JSON_POINTER if the JSONPath cannot be parsed * - NO_SUCH_FIELD if a field does not exist * - INDEX_OUT_OF_BOUNDS if an array index is out of bounds * - INCORRECT_TYPE if path traversal encounters wrong type */ simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; /** * Consumes the document and returns a string_view instance corresponding to the * document as represented in JSON. It points inside the original byte array containing * the JSON document. */ simdjson_inline simdjson_result raw_json() noexcept; #if SIMDJSON_STATIC_REFLECTION /** * Extract only specific fields from the JSON object into a struct. * * This allows selective deserialization of only the fields you need, * potentially improving performance by skipping unwanted fields. * * Example: * ```cpp * struct Car { * std::string make; * std::string model; * int year; * double price; * }; * * Car car; * doc.extract_into<"make", "model">(car); * // Only 'make' and 'model' fields are extracted from JSON * ``` * * @tparam FieldNames Compile-time string literals specifying which fields to extract * @param out The output struct to populate with selected fields * @returns SUCCESS on success, or an error code if a required field is missing or has wrong type */ template requires(std::is_class_v && (sizeof...(FieldNames) > 0)) simdjson_warn_unused simdjson_inline error_code extract_into(T& out) & noexcept; #endif // SIMDJSON_STATIC_REFLECTION protected: /** * Consumes the document. */ simdjson_warn_unused simdjson_inline error_code consume() noexcept; simdjson_inline document(ondemand::json_iterator &&iter) noexcept; simdjson_inline const uint8_t *text(uint32_t idx) const noexcept; simdjson_inline value_iterator resume_value_iterator() noexcept; simdjson_inline value_iterator get_root_value_iterator() noexcept; simdjson_inline simdjson_result start_or_resume_object() noexcept; static simdjson_inline document start(ondemand::json_iterator &&iter) noexcept; // // Fields // json_iterator iter{}; ///< Current position in the document static constexpr depth_t DOCUMENT_DEPTH = 0; ///< document depth is always 0 friend class array_iterator; friend class value; friend class ondemand::parser; friend class object; friend class array; friend class field; friend class token; friend class document_stream; friend class document_reference; }; /** * A document_reference is a thin wrapper around a document reference instance. * The document_reference instances are used primarily/solely for streams of JSON * documents. They differ from document instances when parsing a scalar value * (a document that is not an array or an object). In the case of a document, * we expect the document to be fully consumed. In the case of a document_reference, * we allow trailing content. */ class document_reference { public: simdjson_inline document_reference() noexcept; simdjson_inline document_reference(document &d) noexcept; simdjson_inline document_reference(const document_reference &other) noexcept = default; simdjson_inline document_reference& operator=(const document_reference &other) noexcept = default; simdjson_inline void rewind() noexcept; simdjson_inline simdjson_result get_array() & noexcept; simdjson_inline simdjson_result get_object() & noexcept; simdjson_inline simdjson_result get_uint64() noexcept; simdjson_inline simdjson_result get_uint64_in_string() noexcept; simdjson_inline simdjson_result get_int64() noexcept; simdjson_inline simdjson_result get_int64_in_string() noexcept; simdjson_inline simdjson_result get_double() noexcept; simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; simdjson_inline simdjson_result get_wobbly_string() noexcept; simdjson_inline simdjson_result get_raw_json_string() noexcept; simdjson_inline simdjson_result get_bool() noexcept; simdjson_inline simdjson_result get_value() noexcept; simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & #if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif { static_assert(std::is_default_constructible::value, "Cannot initialize the specified type."); T out{}; SIMDJSON_TRY(get(out)); return out; } template simdjson_inline simdjson_result get() && #if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif { static_assert(!std::is_same::value && !std::is_same::value, "You should never hold either an ondemand::array or ondemand::object without a corresponding ondemand::document_reference being alive; that would be Undefined Behaviour."); return static_cast(*this).get(); } /** * Get this value as the given type. * * Supported types: object, array, raw_json_string, string_view, uint64_t, int64_t, double, bool, value * * Be mindful that the document instance must remain in scope while you are accessing object, array and value instances. * * @param out This is set to a value of the given type, parsed from the JSON. If there is an error, this may not be initialized. * @returns INCORRECT_TYPE If the JSON value is not an object. * @returns SUCCESS If the parse succeeded and the out parameter was set to the value. */ template simdjson_warn_unused simdjson_inline error_code get(T &out) & #if SIMDJSON_SUPPORTS_CONCEPTS noexcept(custom_deserializable ? nothrow_custom_deserializable : true) #else noexcept #endif { #if SIMDJSON_SUPPORTS_CONCEPTS if constexpr (custom_deserializable) { return deserialize(*this, out); } else { static_assert(!sizeof(T), "The get method with type T is not implemented by the simdjson library. " "And you do not seem to have added support for it. Indeed, we have that " "simdjson::custom_deserializable is false and the type T is not a default type " "such as ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " "int64_t, double, or bool."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; } #else // SIMDJSON_SUPPORTS_CONCEPTS // Unless the simdjson library or the user provides an inline implementation, calling this method should // immediately fail. static_assert(!sizeof(T), "The get method with given type is not implemented by the simdjson library. " "The supported types are ondemand::object, ondemand::array, raw_json_string, std::string_view, uint64_t, " "int64_t, double, and bool. We recommend you use get_double(), get_bool(), get_uint64(), get_int64(), " " get_object(), get_array(), get_raw_json_string(), or get_string() instead of the get template." " You may also add support for custom types, see our documentation."); static_cast(out); // to get rid of unused errors return UNINITIALIZED; #endif // SIMDJSON_SUPPORTS_CONCEPTS } /** @overload template error_code get(T &out) & noexcept */ template simdjson_inline error_code get(T &out) && noexcept; simdjson_inline simdjson_result raw_json() noexcept; #if SIMDJSON_STATIC_REFLECTION template requires(std::is_class_v && (sizeof...(FieldNames) > 0)) simdjson_warn_unused simdjson_inline error_code extract_into(T& out) & noexcept; #endif // SIMDJSON_STATIC_REFLECTION simdjson_inline operator document&() const noexcept; #if SIMDJSON_EXCEPTIONS template explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator array() & noexcept(false); simdjson_inline operator object() & noexcept(false); simdjson_inline operator uint64_t() noexcept(false); simdjson_inline operator int64_t() noexcept(false); simdjson_inline operator double() noexcept(false); simdjson_inline operator std::string_view() noexcept(false); simdjson_inline operator raw_json_string() noexcept(false); simdjson_inline operator bool() noexcept(false); simdjson_inline operator value() noexcept(false); #endif simdjson_inline simdjson_result count_elements() & noexcept; simdjson_inline simdjson_result count_fields() & noexcept; simdjson_inline simdjson_result at(size_t index) & noexcept; simdjson_inline simdjson_result begin() & noexcept; simdjson_inline simdjson_result end() & noexcept; simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; simdjson_inline simdjson_result find_field(const char *key) & noexcept; simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; simdjson_inline simdjson_result operator[](const char *key) & noexcept; simdjson_result operator[](int) & noexcept = delete; simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; simdjson_inline simdjson_result find_field_unordered(const char *key) & noexcept; simdjson_inline simdjson_result type() noexcept; simdjson_inline simdjson_result is_scalar() noexcept; simdjson_inline simdjson_result is_string() noexcept; simdjson_inline simdjson_result current_location() noexcept; simdjson_inline int32_t current_depth() const noexcept; simdjson_inline bool is_negative() noexcept; simdjson_inline simdjson_result is_integer() noexcept; simdjson_inline simdjson_result get_number_type() noexcept; simdjson_inline simdjson_result get_number() noexcept; simdjson_inline simdjson_result raw_json_token() noexcept; simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; private: document *doc{nullptr}; }; } // namespace ondemand } // namespace SIMDJSON_IMPLEMENTATION } // namespace simdjson namespace simdjson { template<> struct simdjson_result : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base { public: simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::document &&value) noexcept; ///< @private simdjson_inline simdjson_result(error_code error) noexcept; ///< @private simdjson_inline simdjson_result() noexcept = default; simdjson_inline error_code rewind() noexcept; simdjson_inline simdjson_result get_array() & noexcept; simdjson_inline simdjson_result get_object() & noexcept; simdjson_inline simdjson_result get_uint64() noexcept; simdjson_inline simdjson_result get_uint64_in_string() noexcept; simdjson_inline simdjson_result get_int64() noexcept; simdjson_inline simdjson_result get_int64_in_string() noexcept; simdjson_inline simdjson_result get_double() noexcept; simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; simdjson_inline simdjson_result get_wobbly_string() noexcept; simdjson_inline simdjson_result get_raw_json_string() noexcept; simdjson_inline simdjson_result get_bool() noexcept; simdjson_inline simdjson_result get_value() noexcept; simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & noexcept; template simdjson_deprecated simdjson_inline simdjson_result get() && noexcept; template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS using SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base::operator*; using SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base::operator->; template ::value == false>::type> explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false); simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false); simdjson_inline operator uint64_t() noexcept(false); simdjson_inline operator int64_t() noexcept(false); simdjson_inline operator double() noexcept(false); simdjson_inline operator std::string_view() noexcept(false); simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false); simdjson_inline operator bool() noexcept(false); simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false); #endif simdjson_inline simdjson_result count_elements() & noexcept; simdjson_inline simdjson_result count_fields() & noexcept; simdjson_inline simdjson_result at(size_t index) & noexcept; simdjson_inline simdjson_result begin() & noexcept; simdjson_inline simdjson_result end() & noexcept; simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; simdjson_inline simdjson_result find_field(const char *key) & noexcept; simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; simdjson_inline simdjson_result operator[](const char *key) & noexcept; simdjson_result operator[](int) & noexcept = delete; simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; simdjson_inline simdjson_result find_field_unordered(const char *key) & noexcept; simdjson_inline simdjson_result type() noexcept; simdjson_inline simdjson_result is_scalar() noexcept; simdjson_inline simdjson_result is_string() noexcept; simdjson_inline simdjson_result current_location() noexcept; simdjson_inline int32_t current_depth() const noexcept; simdjson_inline bool at_end() const noexcept; simdjson_inline bool is_negative() noexcept; simdjson_inline simdjson_result is_integer() noexcept; simdjson_inline simdjson_result get_number_type() noexcept; simdjson_inline simdjson_result get_number() noexcept; /** @copydoc simdjson_inline std::string_view document::raw_json_token() const noexcept */ simdjson_inline simdjson_result raw_json_token() noexcept; simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; #if SIMDJSON_STATIC_REFLECTION template requires(std::is_class_v && (sizeof...(FieldNames) > 0)) simdjson_warn_unused simdjson_inline error_code extract_into(T& out) & noexcept; #endif // SIMDJSON_STATIC_REFLECTION }; } // namespace simdjson namespace simdjson { template<> struct simdjson_result : public SIMDJSON_IMPLEMENTATION::implementation_simdjson_result_base { public: simdjson_inline simdjson_result(SIMDJSON_IMPLEMENTATION::ondemand::document_reference value, error_code error) noexcept; simdjson_inline simdjson_result() noexcept = default; simdjson_inline error_code rewind() noexcept; simdjson_inline simdjson_result get_array() & noexcept; simdjson_inline simdjson_result get_object() & noexcept; simdjson_inline simdjson_result get_uint64() noexcept; simdjson_inline simdjson_result get_uint64_in_string() noexcept; simdjson_inline simdjson_result get_int64() noexcept; simdjson_inline simdjson_result get_int64_in_string() noexcept; simdjson_inline simdjson_result get_double() noexcept; simdjson_inline simdjson_result get_double_in_string() noexcept; simdjson_inline simdjson_result get_string(bool allow_replacement = false) noexcept; template simdjson_warn_unused simdjson_inline error_code get_string(string_type& receiver, bool allow_replacement = false) noexcept; simdjson_inline simdjson_result get_wobbly_string() noexcept; simdjson_inline simdjson_result get_raw_json_string() noexcept; simdjson_inline simdjson_result get_bool() noexcept; simdjson_inline simdjson_result get_value() noexcept; simdjson_inline simdjson_result is_null() noexcept; template simdjson_inline simdjson_result get() & noexcept; template simdjson_inline simdjson_result get() && noexcept; template simdjson_inline error_code get(T &out) & noexcept; template simdjson_inline error_code get(T &out) && noexcept; #if SIMDJSON_EXCEPTIONS template explicit simdjson_inline operator T() noexcept(false); simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::array() & noexcept(false); simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::object() & noexcept(false); simdjson_inline operator uint64_t() noexcept(false); simdjson_inline operator int64_t() noexcept(false); simdjson_inline operator double() noexcept(false); simdjson_inline operator std::string_view() noexcept(false); simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::raw_json_string() noexcept(false); simdjson_inline operator bool() noexcept(false); simdjson_inline operator SIMDJSON_IMPLEMENTATION::ondemand::value() noexcept(false); #endif simdjson_inline simdjson_result count_elements() & noexcept; simdjson_inline simdjson_result count_fields() & noexcept; simdjson_inline simdjson_result at(size_t index) & noexcept; simdjson_inline simdjson_result begin() & noexcept; simdjson_inline simdjson_result end() & noexcept; simdjson_inline simdjson_result find_field(std::string_view key) & noexcept; simdjson_inline simdjson_result find_field(const char *key) & noexcept; simdjson_inline simdjson_result operator[](std::string_view key) & noexcept; simdjson_inline simdjson_result operator[](const char *key) & noexcept; simdjson_result operator[](int) & noexcept = delete; simdjson_inline simdjson_result find_field_unordered(std::string_view key) & noexcept; simdjson_inline simdjson_result find_field_unordered(const char *key) & noexcept; simdjson_inline simdjson_result type() noexcept; simdjson_inline simdjson_result is_scalar() noexcept; simdjson_inline simdjson_result is_string() noexcept; simdjson_inline simdjson_result current_location() noexcept; simdjson_inline simdjson_result current_depth() const noexcept; simdjson_inline simdjson_result is_negative() noexcept; simdjson_inline simdjson_result is_integer() noexcept; simdjson_inline simdjson_result get_number_type() noexcept; simdjson_inline simdjson_result get_number() noexcept; /** @copydoc simdjson_inline std::string_view document_reference::raw_json_token() const noexcept */ simdjson_inline simdjson_result raw_json_token() noexcept; simdjson_inline simdjson_result at_pointer(std::string_view json_pointer) noexcept; simdjson_inline simdjson_result at_path(std::string_view json_path) noexcept; simdjson_inline simdjson_result> at_path_with_wildcard(std::string_view json_path) noexcept; #if SIMDJSON_STATIC_REFLECTION template requires(std::is_class_v && (sizeof...(FieldNames) > 0)) simdjson_warn_unused simdjson_inline error_code extract_into(T& out) & noexcept; #endif // SIMDJSON_STATIC_REFLECTION }; } // namespace simdjson #endif // SIMDJSON_GENERIC_ONDEMAND_DOCUMENT_H