#ifndef SIMDJSON_DOM_ELEMENT_H #define SIMDJSON_DOM_ELEMENT_H #include "simdjson/common_defs.h" #include "simdjson/error.h" #include "simdjson/internal/tape_ref.h" #include "simdjson/minify.h" #include namespace simdjson { namespace dom { class array; class document; class object; /** * The actual concrete type of a JSON element * This is the type it is most easily cast to with get<>. */ enum class element_type { ARRAY = '[', ///< dom::array OBJECT = '{', ///< dom::object INT64 = 'l', ///< int64_t UINT64 = 'u', ///< uint64_t: any integer that fits in uint64_t but *not* int64_t DOUBLE = 'd', ///< double: Any number with a "." or "e" that fits in double. STRING = '"', ///< std::string_view BOOL = 't', ///< bool NULL_VALUE = 'n' ///< null }; /** * A JSON element. * * References an element in a JSON document, representing a JSON null, boolean, string, number, * array or object. */ class element { public: /** Create a new, invalid element. */ really_inline element() noexcept; /** The type of this element. */ really_inline element_type type() const noexcept; /** * Cast this element to an array. * * Equivalent to get(). * * @returns An object that can be used to iterate the array, or: * INCORRECT_TYPE if the JSON element is not an array. */ inline simdjson_result get_array() const noexcept; /** * Cast this element to an object. * * Equivalent to get(). * * @returns An object that can be used to look up or iterate the object's fields, or: * INCORRECT_TYPE if the JSON element is not an object. */ inline simdjson_result get_object() const noexcept; /** * Cast this element to a null-terminated C string. * * The string is guaranteed to be valid UTF-8. * * The get_c_str() function is equivalent to get(). * * The length of the string is given by get_string_length(). Because JSON strings * may contain null characters, it may be incorrect to use strlen to determine the * string length. * * It is possible to get a single string_view instance which represents both the string * content and its length: see get_string(). * * @returns A pointer to a null-terminated UTF-8 string. This 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 element is not a string. */ inline simdjson_result get_c_str() const noexcept; /** * Gives the length in bytes of the string. * * It is possible to get a single string_view instance which represents both the string * content and its length: see get_string(). * * @returns A string length in bytes. * Returns INCORRECT_TYPE if the JSON element is not a string. */ inline simdjson_result get_string_length() const noexcept; /** * Cast this element to a string. * * The string is guaranteed to be valid UTF-8. * * Equivalent to get(). * * @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 element is not a string. */ inline simdjson_result get_string() const noexcept; /** * Cast this element to a signed integer. * * Equivalent to get(). * * @returns A signed 64-bit integer. * Returns INCORRECT_TYPE if the JSON element is not an integer, or NUMBER_OUT_OF_RANGE * if it is negative. */ inline simdjson_result get_int64() const noexcept; /** * Cast this element to an unsigned integer. * * Equivalent to get(). * * @returns An unsigned 64-bit integer. * Returns INCORRECT_TYPE if the JSON element is not an integer, or NUMBER_OUT_OF_RANGE * if it is too large. */ inline simdjson_result get_uint64() const noexcept; /** * Cast this element to an double floating-point. * * Equivalent to get(). * * @returns A double value. * Returns INCORRECT_TYPE if the JSON element is not a number. */ inline simdjson_result get_double() const noexcept; /** * Cast this element to a bool. * * Equivalent to get(). * * @returns A bool value. * Returns INCORRECT_TYPE if the JSON element is not a boolean. */ inline simdjson_result get_bool() const noexcept; /** * Whether this element is a json array. * * Equivalent to is(). */ inline bool is_array() const noexcept; /** * Whether this element is a json object. * * Equivalent to is(). */ inline bool is_object() const noexcept; /** * Whether this element is a json string. * * Equivalent to is() or is(). */ inline bool is_string() const noexcept; /** * Whether this element is a json number that fits in a signed 64-bit integer. * * Equivalent to is(). */ inline bool is_int64() const noexcept; /** * Whether this element is a json number that fits in an unsigned 64-bit integer. * * Equivalent to is(). */ inline bool is_uint64() const noexcept; /** * Whether this element is a json number that fits in a double. * * Equivalent to is(). */ inline bool is_double() const noexcept; /** * Whether this element is a json number. * * Both integers and floating points will return true. */ inline bool is_number() const noexcept; /** * Whether this element is a json `true` or `false`. * * Equivalent to is(). */ inline bool is_bool() const noexcept; /** * Whether this element is a json `null`. */ inline bool is_null() const noexcept; /** * Tell whether the value can be cast to provided type (T). * * Supported types: * - Boolean: bool * - Number: double, uint64_t, int64_t * - String: std::string_view, const char * * - Array: dom::array * - Object: dom::object * * @tparam T bool, double, uint64_t, int64_t, std::string_view, const char *, dom::array, dom::object */ template really_inline bool is() const noexcept; /** * Get the value as the provided type (T). * * Supported types: * - Boolean: bool * - Number: double, uint64_t, int64_t * - String: std::string_view, const char * * - Array: dom::array * - Object: dom::object * * @tparam T bool, double, uint64_t, int64_t, std::string_view, const char *, dom::array, dom::object * * @returns The value cast to the given type, or: * INCORRECT_TYPE if the value cannot be cast to the given type. */ template inline simdjson_result get() const noexcept; /** * Get the value as the provided type (T). * * Supported types: * - Boolean: bool * - Number: double, uint64_t, int64_t * - String: std::string_view, const char * * - Array: dom::array * - Object: dom::object * * @tparam T bool, double, uint64_t, int64_t, std::string_view, const char *, dom::array, dom::object * * @param value The variable to set to the value. May not be set if there is an error. * * @returns The error that occurred, or SUCCESS if there was no error. */ template WARN_UNUSED really_inline error_code get(T &value) const noexcept; /** * Get the value as the provided type (T), setting error if it's not the given type. * * Supported types: * - Boolean: bool * - Number: double, uint64_t, int64_t * - String: std::string_view, const char * * - Array: dom::array * - Object: dom::object * * @tparam T bool, double, uint64_t, int64_t, std::string_view, const char *, dom::array, dom::object * * @param value The variable to set to the given type. value is undefined if there is an error. * @param error The variable to store the error. error is set to error_code::SUCCEED if there is an error. */ template inline void tie(T &value, error_code &error) && noexcept; #if SIMDJSON_EXCEPTIONS /** * Read this element as a boolean. * * @return The boolean value * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a boolean. */ inline operator bool() const noexcept(false); /** * Read this element as a null-terminated UTF-8 string. * * Be mindful that JSON allows strings to contain null characters. * * Does *not* convert other types to a string; requires that the JSON type of the element was * an actual string. * * @return The string value. * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a string. */ inline explicit operator const char*() const noexcept(false); /** * Read this element as a null-terminated UTF-8 string. * * Does *not* convert other types to a string; requires that the JSON type of the element was * an actual string. * * @return The string value. * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a string. */ inline operator std::string_view() const noexcept(false); /** * Read this element as an unsigned integer. * * @return The integer value. * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an integer * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits or is negative */ inline operator uint64_t() const noexcept(false); /** * Read this element as an signed integer. * * @return The integer value. * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an integer * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits */ inline operator int64_t() const noexcept(false); /** * Read this element as an double. * * @return The double value. * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not a number * @exception simdjson_error(NUMBER_OUT_OF_RANGE) if the integer doesn't fit in 64 bits or is negative */ inline operator double() const noexcept(false); /** * Read this element as a JSON array. * * @return The JSON array. * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an array */ inline operator array() const noexcept(false); /** * Read this element as a JSON object (key/value pairs). * * @return The JSON object. * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an object */ inline operator object() const noexcept(false); /** * Iterate over each element in this array. * * @return The beginning of the iteration. * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an array */ inline dom::array::iterator begin() const noexcept(false); /** * Iterate over each element in this array. * * @return The end of the iteration. * @exception simdjson_error(INCORRECT_TYPE) if the JSON element is not an array */ inline dom::array::iterator end() const noexcept(false); #endif // SIMDJSON_EXCEPTIONS /** * Get the value associated with the given key. * * The key will be matched against **unescaped** JSON: * * dom::parser parser; * parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get().first == 1 * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get().error() == NO_SUCH_FIELD * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object * - INCORRECT_TYPE if this is not an object */ inline simdjson_result operator[](const std::string_view &key) const noexcept; /** * Get the value associated with the given key. * * The key will be matched against **unescaped** JSON: * * dom::parser parser; * parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get().first == 1 * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get().error() == NO_SUCH_FIELD * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object * - INCORRECT_TYPE if this is not an object */ inline simdjson_result operator[](const char *key) const noexcept; /** * Get the value associated with the given JSON pointer. * * dom::parser parser; * element doc = parser.parse(R"({ "foo": { "a": [ 10, 20, 30 ] }})"_padded); * doc.at("/foo/a/1") == 20 * doc.at("/")["foo"]["a"].at(1) == 20 * doc.at("")["foo"]["a"].at(1) == 20 * * @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 */ inline simdjson_result at(const std::string_view &json_pointer) const noexcept; /** * Get the value at the given index. * * @return The value at the given index, or: * - INDEX_OUT_OF_BOUNDS if the array index is larger than an array length */ inline simdjson_result at(size_t index) const noexcept; /** * Get the value associated with the given key. * * The key will be matched against **unescaped** JSON: * * dom::parser parser; * parser.parse(R"({ "a\n": 1 })"_padded)["a\n"].get().first == 1 * parser.parse(R"({ "a\n": 1 })"_padded)["a\\n"].get().error() == NO_SUCH_FIELD * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object */ inline simdjson_result at_key(const std::string_view &key) const noexcept; /** * Get the value associated with the given key in a case-insensitive manner. * * Note: The key will be matched against **unescaped** JSON. * * @return The value associated with this field, or: * - NO_SUCH_FIELD if the field does not exist in the object */ inline simdjson_result at_key_case_insensitive(const std::string_view &key) const noexcept; /** @private for debugging. Prints out the root element. */ inline bool dump_raw_tape(std::ostream &out) const noexcept; private: really_inline element(const internal::tape_ref &tape) noexcept; internal::tape_ref tape; friend class document; friend class object; friend class array; friend struct simdjson_result; template friend class simdjson::minifier; }; /** * Print JSON to an output stream. * * By default, the value will be printed minified. * * @param out The output stream. * @param value The value to print. * @throw if there is an error with the underlying output stream. simdjson itself will not throw. */ inline std::ostream& operator<<(std::ostream& out, const element &value); /** * Print element type to an output stream. * * @param out The output stream. * @param value The value to print. * @throw if there is an error with the underlying output stream. simdjson itself will not throw. */ inline std::ostream& operator<<(std::ostream& out, element_type type); } // namespace dom /** The result of a JSON navigation that may fail. */ template<> struct simdjson_result : public internal::simdjson_result_base { public: really_inline simdjson_result() noexcept; ///< @private really_inline simdjson_result(dom::element &&value) noexcept; ///< @private really_inline simdjson_result(error_code error) noexcept; ///< @private really_inline simdjson_result type() const noexcept; template really_inline bool is() const noexcept; template really_inline simdjson_result get() const noexcept; template WARN_UNUSED really_inline error_code get(T &value) const noexcept; really_inline simdjson_result get_array() const noexcept; really_inline simdjson_result get_object() const noexcept; really_inline simdjson_result get_c_str() const noexcept; really_inline simdjson_result get_string_length() const noexcept; really_inline simdjson_result get_string() const noexcept; really_inline simdjson_result get_int64() const noexcept; really_inline simdjson_result get_uint64() const noexcept; really_inline simdjson_result get_double() const noexcept; really_inline simdjson_result get_bool() const noexcept; really_inline bool is_array() const noexcept; really_inline bool is_object() const noexcept; really_inline bool is_string() const noexcept; really_inline bool is_int64() const noexcept; really_inline bool is_uint64() const noexcept; really_inline bool is_double() const noexcept; really_inline bool is_bool() const noexcept; really_inline bool is_null() const noexcept; really_inline simdjson_result operator[](const std::string_view &key) const noexcept; really_inline simdjson_result operator[](const char *key) const noexcept; really_inline simdjson_result at(const std::string_view &json_pointer) const noexcept; really_inline simdjson_result at(size_t index) const noexcept; really_inline simdjson_result at_key(const std::string_view &key) const noexcept; really_inline simdjson_result at_key_case_insensitive(const std::string_view &key) const noexcept; #if SIMDJSON_EXCEPTIONS really_inline operator bool() const noexcept(false); really_inline explicit operator const char*() const noexcept(false); really_inline operator std::string_view() const noexcept(false); really_inline operator uint64_t() const noexcept(false); really_inline operator int64_t() const noexcept(false); really_inline operator double() const noexcept(false); really_inline operator dom::array() const noexcept(false); really_inline operator dom::object() const noexcept(false); really_inline dom::array::iterator begin() const noexcept(false); really_inline dom::array::iterator end() const noexcept(false); #endif // SIMDJSON_EXCEPTIONS }; #if SIMDJSON_EXCEPTIONS /** * Print JSON to an output stream. * * By default, the value will be printed minified. * * @param out The output stream. * @param value The value to print. * @throw simdjson_error if the result being printed has an error. If there is an error with the * underlying output stream, that error will be propagated (simdjson_error will not be * thrown). */ really_inline std::ostream& operator<<(std::ostream& out, const simdjson_result &value) noexcept(false); #endif } // namespace simdjson #endif // SIMDJSON_DOM_DOCUMENT_H