diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 0e76487a4..d0d9610f4 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -420,7 +420,7 @@ inline void to_json(BasicJsonType& j, const EnumKeyedMap& map) auto& key_string = *key.template get_ptr(); if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second)) { - JSON_THROW(type_error::create(318, concat("duplicate object key '", key_string, "'"), &key)); + JSON_THROW(type_error::create(exception_id::enum_key_duplicate, concat("duplicate object key '", key_string, "'"), &key)); } } external_constructor::construct(j, std::move(obj)); diff --git a/include/nlohmann/detail/exceptions.hpp b/include/nlohmann/detail/exceptions.hpp index 43094ead5..f2c6651c4 100644 --- a/include/nlohmann/detail/exceptions.hpp +++ b/include/nlohmann/detail/exceptions.hpp @@ -45,6 +45,84 @@ namespace detail // exceptions // //////////////// +/*! +@brief the ids of the exceptions thrown by the library +@note The values are part of the public API: they are the `id` member of the + exceptions and appear in their `what()` messages. +@sa https://json.nlohmann.me/home/exceptions/ +*/ +enum class exception_id : int +{ + // parse_error + syntax_error = 101, ///< unexpected token or invalid literal while parsing JSON + patch_not_an_array = 104, ///< a JSON Patch document is not an array of objects + patch_invalid_operation = 105, ///< a JSON Patch operation is malformed + pointer_index_leading_zero = 106, ///< a JSON Pointer array index has a leading zero + pointer_missing_slash = 107, ///< a JSON Pointer does not start with '/' + pointer_invalid_escape = 108, ///< a JSON Pointer contains an escape other than ~0 and ~1 + pointer_index_not_a_number = 109, ///< a JSON Pointer array index is not a number + unexpected_end_of_input = 110, ///< a binary input ends early, or has bytes left at its end + unexpected_byte = 112, ///< a binary input contains an unexpected byte or invalid length + invalid_string_or_size = 113, ///< a binary input contains an invalid string or size specification + bson_unsupported_type = 114, ///< a BSON record type is not supported + invalid_high_precision_number = 115, ///< a UBJSON/BJData high-precision number cannot be parsed + // invalid_iterator + iterators_incompatible = 201, ///< the iterators of a range belong to different values + iterator_from_other_value = 202, ///< an iterator does not belong to the value it is used with + iterator_range_from_other_value = 203, ///< an iterator range does not belong to the value it is used with + iterator_range_out_of_range = 204, ///< an iterator range of a primitive value is not [begin, end) + iterator_out_of_range = 205, ///< an iterator of a primitive value is not begin() + iterator_range_of_null = 206, ///< an iterator range belongs to a null value + iterator_key_not_object = 207, ///< key() is called on an iterator of a non-object + iterator_subscript_on_object = 208, ///< operator[] is called on an iterator of an object + iterator_arithmetic_on_object = 209, ///< an offset operator is used on an iterator of an object + insert_range_incompatible = 210, ///< the iterators of an inserted range belong to different values + insert_range_into_itself = 211, ///< an inserted range belongs to the value it is inserted into + iterators_compare_different_values = 212, ///< iterators of different values are compared + iterator_order_on_object = 213, ///< iterators of an object are compared by order + iterator_value_unavailable = 214, ///< an iterator does not refer to a value + // type_error + object_from_non_pairs = 301, ///< an object is created from an initializer list that is not a list of pairs + type_mismatch = 302, ///< a value has the wrong type for a conversion + incompatible_reference_type = 303, ///< get_ref() is called with a reference type that does not match the value + at_wrong_type = 304, ///< at() is called on a value of the wrong type + subscript_wrong_type = 305, ///< operator[] is called on a value of the wrong type + value_wrong_type = 306, ///< value() is called on a value of the wrong type + erase_wrong_type = 307, ///< erase() is called on a value of the wrong type + push_back_wrong_type = 308, ///< push_back() or operator+= is called on a value of the wrong type + insert_wrong_type = 309, ///< insert() is called on a value of the wrong type + swap_wrong_type = 310, ///< swap() is called on a value of the wrong type + emplace_wrong_type = 311, ///< emplace() or emplace_back() is called on a value of the wrong type + update_wrong_type = 312, ///< update() is called on a value of the wrong type + unflatten_invalid_value = 313, ///< unflatten() finds conflicting paths + unflatten_not_object = 314, ///< unflatten() is called on a non-object + unflatten_value_not_primitive = 315, ///< unflatten() is called on an object with non-primitive values + invalid_utf8 = 316, ///< dump() finds a string that is not valid UTF-8 + type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format + enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string + discarded_value_used = 321, ///< a discarded value is used + // out_of_range + array_index_out_of_range = 401, ///< an array index is out of range + pointer_past_the_end_index = 402, ///< a JSON Pointer uses the array index '-' + key_not_found = 403, ///< an object key is not found + pointer_unresolved = 404, ///< a JSON Pointer reference token cannot be resolved + patch_on_root = 405, ///< the root of a value has no parent, e.g. for a JSON Patch 'remove' or 'add' at the root + number_overflow = 406, ///< a number cannot be stored without overflowing to NaN or INF + integer_too_large = 407, ///< an integer cannot be represented in the binary format + container_too_large = 408, ///< the size of a container in a binary input exceeds the maximal capacity + bson_key_with_null = 409, ///< a BSON key contains U+0000 + value_out_of_range = 410, ///< an enum value is undefined, or a JSON Pointer array index exceeds size_type + patch_add_parent_not_container = 411, ///< the parent of a JSON Patch 'add' target is not a container + length_too_large = 412, ///< a length does not fit into the length field of a binary format + patch_remove_parent_not_container = 413, ///< the parent of a JSON Patch 'remove' target is not a container + patch_move_into_child = 414, ///< a JSON Patch 'move' moves a value into one of its children + subtype_out_of_range = 415, ///< a binary subtype does not fit into one byte + // other_error + internal_error = 500, ///< unreachable code was reached + patch_test_failed = 501, ///< a JSON Patch 'test' operation failed + size_marker_required = 502 ///< UBJSON/BJData output with type markers requires size markers +}; + /// @brief general exception of the @ref basic_json class /// @sa https://json.nlohmann.me/api/basic_json/exception/ class exception : public std::exception @@ -195,6 +273,18 @@ class parse_error : public exception return {id_, byte_, w.c_str()}; } + template::value, int> = 0> + static parse_error create(exception_id id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), pos, what_arg, context); + } + + template::value, int> = 0> + static parse_error create(exception_id id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), byte_, what_arg, context); + } + /*! @brief byte index of the parse error @@ -229,6 +319,12 @@ class invalid_iterator : public exception return {id_, w.c_str()}; } + template::value, int> = 0> + static invalid_iterator create(exception_id id_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), what_arg, context); + } + private: JSON_HEDLEY_NON_NULL(3) invalid_iterator(int id_, const char* what_arg) @@ -247,6 +343,12 @@ class type_error : public exception return {id_, w.c_str()}; } + template::value, int> = 0> + static type_error create(exception_id id_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), what_arg, context); + } + private: JSON_HEDLEY_NON_NULL(3) type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} @@ -264,6 +366,12 @@ class out_of_range : public exception return {id_, w.c_str()}; } + template::value, int> = 0> + static out_of_range create(exception_id id_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), what_arg, context); + } + private: JSON_HEDLEY_NON_NULL(3) out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} @@ -281,6 +389,12 @@ class other_error : public exception return {id_, w.c_str()}; } + template::value, int> = 0> + static other_error create(exception_id id_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), what_arg, context); + } + private: JSON_HEDLEY_NON_NULL(3) other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} @@ -318,18 +432,18 @@ JSON_HEDLEY_NO_RETURN inline void throw_type_must_be(const char* expected, const { static_cast(expected); // unused when JSON_NOEXCEPTION is defined static_cast(j); - JSON_THROW(type_error::create(302, concat("type must be ", expected, ", but is ", j.type_name()), &j)); + JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), &j)); } /*! @brief throws because an operation is not supported for the type of @a j -@param[in] id_ the id of the type_error exception (304..312) +@param[in] id_ the id of the type_error exception (at_wrong_type..update_wrong_type) @param[in] operation the operation, e.g. "erase()" @param[in] j the value the operation was called on @throw type_error always */ template -JSON_HEDLEY_NO_RETURN inline void throw_cannot_use_with(const int id_, const char* operation, const BasicJsonType& j) +JSON_HEDLEY_NO_RETURN inline void throw_cannot_use_with(const exception_id id_, const char* operation, const BasicJsonType& j) { static_cast(id_); // unused when JSON_NOEXCEPTION is defined static_cast(operation); diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 65f2c2123..2a20f4416 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -195,7 +195,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(current != char_traits::eof())) { - return last_byte_error(110, concat("expected end of input; last byte: 0x", get_token_string()), "value"); + return last_byte_error(exception_id::unexpected_end_of_input, concat("expected end of input; last byte: 0x", get_token_string()), "value"); } } @@ -317,7 +317,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast(document_size) != chars_read - document_start)) { - return last_byte_error(112, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"); + return last_byte_error(exception_id::unexpected_byte, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"); } return true; } @@ -509,7 +509,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(len < 1)) { - return last_byte_error(112, concat("string length must be at least 1, is ", std::to_string(len)), "string"); + return last_byte_error(exception_id::unexpected_byte, concat("string length must be at least 1, is ", std::to_string(len)), "string"); } if (JSON_HEDLEY_UNLIKELY(!get_string(len - static_cast(1), result))) @@ -519,7 +519,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(get() != 0x00)) { - return last_byte_error(112, "BSON string is not null-terminated", "string"); + return last_byte_error(exception_id::unexpected_byte, "BSON string is not null-terminated", "string"); } return check_string_utf8(result, "string"); @@ -539,7 +539,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(len < 0)) { - return last_byte_error(112, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"); + return last_byte_error(exception_id::unexpected_byte, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"); } // All BSON binary values have a subtype @@ -631,7 +631,7 @@ class binary_reader { const std::string cr_str = hex_byte(static_cast(element_type)); return sax->parse_error(element_type_parse_position, cr_str, - parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)); + parse_error::create(exception_id::bson_unsupported_type, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)); } } } @@ -955,7 +955,7 @@ class binary_reader { if (tag_handler == cbor_tag_handler_t::error) { - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } // ignore and store: the tag value is already in the head, so @@ -975,7 +975,7 @@ class binary_reader { case cbor_tag_handler_t::error: { - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } case cbor_tag_handler_t::ignore: @@ -1049,7 +1049,7 @@ class binary_reader default: // anything else (0xFF is handled inside the other types) { - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } } } @@ -1062,7 +1062,7 @@ class binary_reader */ bool cbor_indefinite_string_error(const char* type_name, const char* context) { - return last_byte_error(113, concat("indefinite-length ", type_name, " is not allowed inside indefinite-length ", type_name, "; last byte: 0x", get_token_string()), context); + return last_byte_error(exception_id::invalid_string_or_size, concat("indefinite-length ", type_name, " is not allowed inside indefinite-length ", type_name, "; last byte: 0x", get_token_string()), context); } /*! @@ -1139,7 +1139,7 @@ class binary_reader default: { - return last_byte_error(113, concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", get_token_string()), "string"); + return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", get_token_string()), "string"); } } } @@ -1269,7 +1269,7 @@ class binary_reader break; } - return last_byte_error(113, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key"); + return last_byte_error(exception_id::invalid_string_or_size, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key"); } /*! @@ -1350,7 +1350,7 @@ class binary_reader default: { - return last_byte_error(113, concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", get_token_string()), "binary"); + return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", get_token_string()), "binary"); } } } @@ -1496,7 +1496,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(len) || len == detail::unknown_size())) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message(concat("excessive ", context, " size"), "size"), nullptr)); } result = conditional_static_cast(len); @@ -1984,7 +1984,7 @@ class binary_reader default: // anything else { - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } } } @@ -2065,7 +2065,7 @@ class binary_reader default: { - return last_byte_error(113, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", get_token_string()), "string"); + return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", get_token_string()), "string"); } } } @@ -2157,7 +2157,7 @@ class binary_reader break; } - return last_byte_error(113, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key"); + return last_byte_error(exception_id::invalid_string_or_size, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key"); } /*! @@ -2466,7 +2466,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(len < 0)) { - return last_byte_error(113, "string length must not be negative", "string"); + return last_byte_error(exception_id::invalid_string_or_size, "string length must not be negative", "string"); } return true; } @@ -2566,10 +2566,7 @@ class binary_reader default: break; } - const char* expected = input_format != input_format_t::bjdata - ? "expected length type specification (U, i, I, l, L)" - : "expected length type specification (U, i, u, I, m, l, M, L)"; - return last_byte_error(113, concat(expected, "; last byte: 0x", get_token_string()), "string"); + return length_type_error("", "string"); } /*! @@ -2654,11 +2651,11 @@ class binary_reader } if (JSON_HEDLEY_UNLIKELY(number < 0)) { - return last_byte_error(113, "count in an optimized container must be positive", "size"); + return last_byte_error(exception_id::invalid_string_or_size, "count in an optimized container must be positive", "size"); } if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(number))) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("integer value overflow", "size"), nullptr)); } result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char @@ -2751,7 +2748,7 @@ class binary_reader } if (!value_in_range_of(number)) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("integer value overflow", "size"), nullptr)); } result = detail::conditional_static_cast(number); @@ -2766,7 +2763,7 @@ class binary_reader } if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array { - return last_byte_error(113, "ndarray dimensional vector is not allowed", "size"); + return last_byte_error(exception_id::invalid_string_or_size, "ndarray dimensional vector is not allowed", "size"); } std::vector dim; if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) @@ -2806,7 +2803,7 @@ class binary_reader // or SIZE_MAX. if (JSON_HEDLEY_UNLIKELY(result > (std::numeric_limits::max)() / i)) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); } result *= i; // the pre-check above already rules out result becoming 0 @@ -2815,7 +2812,7 @@ class binary_reader // unknown-size container (see get_ubjson_size_type()) if (result == npos) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); } if (JSON_HEDLEY_UNLIKELY(!emit_unsigned(i))) { @@ -2832,10 +2829,7 @@ class binary_reader default: break; } - const char* expected = input_format != input_format_t::bjdata - ? "expected length type specification (U, i, I, l, L) after '#'" - : "expected length type specification (U, i, u, I, m, l, M, L) after '#'"; - return last_byte_error(113, concat(expected, "; last byte: 0x", get_token_string()), "size"); + return length_type_error(" after '#'", "size"); } /*! @@ -2868,7 +2862,7 @@ class binary_reader if (input_format == input_format_t::bjdata && JSON_HEDLEY_UNLIKELY(is_bjd_excluded_optimized_type(result.second))) { - return last_byte_error(112, concat("marker 0x", get_token_string(), " is not a permitted optimized array type"), "type"); + return last_byte_error(exception_id::unexpected_byte, concat("marker 0x", get_token_string(), " is not a permitted optimized array type"), "type"); } if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type"))) @@ -2883,7 +2877,7 @@ class binary_reader { return false; } - return last_byte_error(112, concat("expected '#' after type information; last byte: 0x", get_token_string()), "size"); + return last_byte_error(exception_id::unexpected_byte, concat("expected '#' after type information; last byte: 0x", get_token_string()), "size"); } const bool is_error = get_ubjson_size_value(result.first, is_ndarray); @@ -2902,7 +2896,7 @@ class binary_reader const bool is_error = get_ubjson_size_value(result.first, is_ndarray); if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray) { - return last_byte_error(112, "ndarray requires both type and size", "size"); + return last_byte_error(exception_id::unexpected_byte, "ndarray requires both type and size", "size"); } return is_error; } @@ -3034,7 +3028,7 @@ class binary_reader } if (JSON_HEDLEY_UNLIKELY(current > 127)) { - return last_byte_error(113, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", get_token_string()), "char"); + return last_byte_error(exception_id::invalid_string_or_size, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", get_token_string()), "char"); } string_t s(1, static_cast(current)); return sax->string(s); @@ -3055,7 +3049,7 @@ class binary_reader default: // anything else break; } - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } /*! @@ -3079,7 +3073,7 @@ class binary_reader string_t key = "_ArrayType_"; if (JSON_HEDLEY_UNLIKELY(type_name == nullptr)) { - return unexpected_byte("invalid byte", "type"); + return invalid_byte("type"); } string_t type = type_name; // sax->string() takes a reference @@ -3126,7 +3120,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY((size_and_type.second == 'Z' || size_and_type.second == 'T' || size_and_type.second == 'F') && size_and_type.first > max_valueless_container_size)) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive array size", "size"), nullptr)); } @@ -3162,7 +3156,7 @@ class binary_reader // do not accept ND-array size in objects in BJData if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) { - return last_byte_error(112, "BJData object does not support ND-array size in optimized format", "object"); + return last_byte_error(exception_id::unexpected_byte, "BJData object does not support ND-array size in optimized format", "object"); } if (size_and_type.first != npos) @@ -3199,7 +3193,7 @@ class binary_reader // the lexer would stop at a NUL and accept the digits before it if (JSON_HEDLEY_UNLIKELY(current == '\0')) { - return sax->parse_error(chars_read, "00", parse_error::create(115, chars_read, + return sax->parse_error(chars_read, "00", parse_error::create(exception_id::invalid_high_precision_number, chars_read, exception_message("invalid number text; last byte: 0x00", "high-precision number"), nullptr)); } number_vector.push_back(static_cast(current)); @@ -3216,7 +3210,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) { - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + return sax->parse_error(chars_read, number_string, parse_error::create(exception_id::invalid_high_precision_number, chars_read, exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); } @@ -3234,7 +3228,7 @@ class binary_reader return sax->parse_error( chars_read, number_string, - out_of_range::create(406, concat("number overflow parsing '", number_string, '\''), nullptr)); + out_of_range::create(exception_id::number_overflow, concat("number overflow parsing '", number_string, '\''), nullptr)); } // number_string is a std::string, while the SAX interface takes a // string_t; convert explicitly, as the two are only implicitly @@ -3256,7 +3250,7 @@ class binary_reader case token_type::end_of_input: case token_type::literal_or_value: default: - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + return sax->parse_error(chars_read, number_string, parse_error::create(exception_id::invalid_high_precision_number, chars_read, exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); } } @@ -3530,7 +3524,7 @@ class binary_reader } // 0xFE: end of container where a value is expected - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } /*! @@ -3839,7 +3833,7 @@ class binary_reader { // in case of failure, advance position by 1 to report the failing location ++chars_read; - sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr)); + sax->parse_error(chars_read, "", parse_error::create(exception_id::unexpected_end_of_input, chars_read, exception_message("unexpected end of input", context), nullptr)); return false; } return true; @@ -3993,7 +3987,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(std::isfinite(number) && !std::isfinite(result))) { return sax->parse_error(chars_read, get_token_string(), - out_of_range::create(406, exception_message("number overflow", "value"), nullptr)); + out_of_range::create(exception_id::number_overflow, exception_message("number overflow", "value"), nullptr)); } return sax->number_float(result, ""); } @@ -4113,7 +4107,7 @@ class binary_reader if (error_handler == error_handler_t::strict) { - return last_byte_error(113, "invalid string: ill-formed UTF-8 byte", context); + return last_byte_error(exception_id::invalid_string_or_size, "invalid string: ill-formed UTF-8 byte", context); } result = sanitize_utf8(result, error_handler); @@ -4209,7 +4203,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(current == char_traits::eof())) { return sax->parse_error(chars_read, "", - parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr)); + parse_error::create(exception_id::unexpected_end_of_input, chars_read, exception_message("unexpected end of input", context), nullptr)); } return true; } @@ -4221,7 +4215,7 @@ class binary_reader @param[in] context further context information @return the result of the SAX parser's parse_error() */ - bool last_byte_error(const int id_, const std::string& detail, const std::string& context) const + bool last_byte_error(const exception_id id_, const std::string& detail, const std::string& context) const { return sax->parse_error(chars_read, get_token_string(), parse_error::create(id_, chars_read, exception_message(detail, context), nullptr)); } @@ -4234,7 +4228,30 @@ class binary_reader */ bool unexpected_byte(const char* detail, const std::string& context) const { - return last_byte_error(112, concat(detail, ": 0x", get_token_string()), context); + return last_byte_error(exception_id::unexpected_byte, concat(detail, ": 0x", get_token_string()), context); + } + + /*! + @brief reports the last read byte as invalid (parse_error.112) + @param[in] context further context information + @return the result of the SAX parser's parse_error() + */ + bool invalid_byte(const char* context) const + { + return unexpected_byte("invalid byte", context); + } + + /*! + @brief reports that the last read byte is not a UBJSON/BJData length type (parse_error.113) + @param[in] position where the length type was expected, e.g. " after '#'" + @param[in] context further context information + @return the result of the SAX parser's parse_error() + */ + bool length_type_error(const char* position, const char* context) const + { + const char* types = input_format == input_format_t::bjdata ? "U, i, u, I, m, l, M, L" : "U, i, I, l, L"; + return last_byte_error(exception_id::invalid_string_or_size, + concat("expected length type specification (", types, ")", position, "; last byte: 0x", get_token_string()), context); } /*! diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 9578e275a..847890f7a 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -581,7 +581,7 @@ class wide_string_input_adapter template JSON_HEDLEY_NO_RETURN std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1) { - JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr)); + JSON_THROW(parse_error::create(exception_id::unexpected_byte, 1, "wide string type cannot be interpreted as binary data", nullptr)); } private: @@ -793,7 +793,7 @@ inline file_input_adapter input_adapter(std::FILE* file) { if (file == nullptr) { - JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); } return file_input_adapter(file); } @@ -802,7 +802,7 @@ inline input_stream_adapter input_adapter(std::istream& stream) { if (stream.rdbuf() == nullptr) { - JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); } return input_stream_adapter(stream); } @@ -827,7 +827,7 @@ contiguous_bytes_input_adapter input_adapter(CharT b) { if (b == nullptr) { - JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); } auto length = std::strlen(reinterpret_cast(b)); const auto* ptr = reinterpret_cast(b); diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 2c09ffdbd..816359a60 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -192,7 +192,7 @@ bool check_container_size(SAX& sax, std::size_t len, const char* kind, BasicJson { if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref->max_size())) { - return sax.parse_error(0, "", out_of_range::create(408, concat("excessive ", kind, " size: ", std::to_string(len)), ref)); + return sax.parse_error(0, "", out_of_range::create(exception_id::container_too_large, concat("excessive ", kind, " size: ", std::to_string(len)), ref)); } return true; } diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 8563d5e7f..0b3923610 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -298,7 +298,7 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); + out_of_range::create(exception_id::number_overflow, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); } if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) @@ -519,7 +519,7 @@ class parser bool syntax_error(SAX& sax, const std::string& message) { return sax.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), message, nullptr)); + parse_error::create(exception_id::syntax_error, m_lexer.get_position(), message, nullptr)); } std::string exception_message(const token_type expected, const std::string& context) diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index b6462686a..52b459ad2 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -282,7 +282,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /// @throw invalid_iterator.214 always JSON_HEDLEY_NO_RETURN void throw_cannot_get_value() const { - JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_value_unavailable, "cannot get value", m_object)); } public: @@ -484,7 +484,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci // if objects are not the same, the comparison is undefined if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object)); } // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 @@ -533,7 +533,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci // if objects are not the same, the comparison is undefined if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object)); } // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 @@ -546,7 +546,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci switch (m_object->m_data.m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_order_on_object, "cannot compare order of object iterators", m_object)); case value_t::array: return (m_it.array_iterator < other.m_it.array_iterator); @@ -602,7 +602,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci switch (m_object->m_data.m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object)); case value_t::array: { @@ -681,7 +681,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci switch (m_object->m_data.m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object)); case value_t::array: return m_it.array_iterator - other.m_it.array_iterator; @@ -710,7 +710,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci switch (m_object->m_data.m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_subscript_on_object, "cannot use operator[] for object iterators", m_object)); case value_t::array: return *std::next(m_it.array_iterator, n); @@ -750,7 +750,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci return m_it.object_iterator->first; } - JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_key_not_object, "cannot use key() for non-object iterators", m_object)); } /*! diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 96143a8ed..063bbf623 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -247,7 +247,7 @@ class json_pointer /// @throw out_of_range.405 always JSON_HEDLEY_NO_RETURN static void throw_no_parent() { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + JSON_THROW(detail::out_of_range::create(detail::exception_id::patch_on_root, "JSON pointer has no parent", nullptr)); } /// @throw out_of_range.404 always @@ -256,7 +256,7 @@ class json_pointer { static_cast(reference_token); // unused when JSON_NOEXCEPTION is defined static_cast(context); - JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), context)); + JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_unresolved, detail::concat("unresolved reference token '", reference_token, "'"), context)); } /*! @@ -344,13 +344,13 @@ class json_pointer // the branches differ in their messages, not after JSON_THROW's expansion // NOLINTNEXTLINE(bugprone-branch-clone) case array_index_status::leading_zero: - JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_leading_zero, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); case array_index_status::not_a_number: - JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_not_a_number, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); case array_index_status::unresolved: throw_unresolved(s, nullptr); case array_index_status::exceeds_size_type: - JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); + JSON_THROW(detail::out_of_range::create(detail::exception_id::value_out_of_range, detail::concat("array index ", s, " exceeds size_type"), nullptr)); case array_index_status::ok: default: break; @@ -452,7 +452,7 @@ class json_pointer case detail::value_t::binary: case detail::value_t::discarded: default: - JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); + JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_invalid_value, "invalid value to unflatten", &j)); } prefix.push_back(reference_token); @@ -567,7 +567,7 @@ class json_pointer if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, detail::concat( + JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_past_the_end_index, detail::concat( "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } @@ -576,7 +576,7 @@ class json_pointer // Bounds check before access to avoid exception with JSON_NOEXCEPTION if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size())) { - JSON_THROW(detail::out_of_range::create(401, detail::concat( + JSON_THROW(detail::out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat( "array index ", std::to_string(idx), " is out of range"), ptr)); } ptr = &ptr->operator[](idx); @@ -636,7 +636,7 @@ class json_pointer if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" cannot be used for const access - JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); + JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_past_the_end_index, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } // use unchecked array access; the const operator[] @@ -709,9 +709,9 @@ class json_pointer // the branches differ in their messages, not after JSON_THROW's expansion // NOLINTNEXTLINE(bugprone-branch-clone) case array_index_status::leading_zero: - JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_leading_zero, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr)); case array_index_status::not_a_number: - JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", reference_token, "' is not a number"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_not_a_number, 0, detail::concat("array index '", reference_token, "' is not a number"), nullptr)); case array_index_status::unresolved: case array_index_status::exceeds_size_type: return nullptr; @@ -838,7 +838,7 @@ class json_pointer // check if a nonempty reference string begins with slash if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) { - JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_missing_slash, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); } // extract the reference tokens: @@ -874,7 +874,7 @@ class json_pointer (reference_token[pos + 1] != '0' && reference_token[pos + 1] != '1'))) { - JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_invalid_escape, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); } } @@ -971,7 +971,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(!value.is_object())) { - JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value)); + JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_not_object, "only objects can be unflattened", &value)); } BasicJsonType result; @@ -999,7 +999,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) { - JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); + JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_value_not_primitive, "values in object must be primitive", &element.second)); } // Assign the value to the reference pointed to by JSON pointer. Note diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 1a847e1a9..f5f6473b9 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -312,7 +312,7 @@ return ej_pair.first == e; \ }); \ if (it != std::end(m)) j = it->second; \ - else ::nlohmann::detail::templated_json_throw(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE, nullptr)); \ + else ::nlohmann::detail::templated_json_throw(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range,"enum value out of range for " #ENUM_TYPE, nullptr)); \ } \ template \ inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ @@ -327,7 +327,7 @@ return ej_pair.second == j; \ }); \ if (it != std::end(m)) e = it->first; \ - else ::nlohmann::detail::templated_json_throw(nlohmann::detail::out_of_range::create(410, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \ + else ::nlohmann::detail::templated_json_throw(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \ } // Ugly macros to avoid uglier copy-paste when specializing basic_json. They diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index c4adf47a6..3c4df5293 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -150,7 +150,7 @@ class binary_writer case value_t::discarded: default: { - JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j)); + JSON_THROW(type_error::create(exception_id::type_not_serializable, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j)); } } } @@ -338,7 +338,7 @@ class binary_writer { if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(length))) { - JSON_THROW(out_of_range::create(412, concat("MessagePack length ", std::to_string(length), " exceeds maximum of ", std::to_string((std::numeric_limits::max)())), &j)); + JSON_THROW(out_of_range::create(exception_id::length_too_large, concat("MessagePack length ", std::to_string(length), " exceeds maximum of ", std::to_string((std::numeric_limits::max)())), &j)); } static_cast(j); @@ -604,7 +604,7 @@ class binary_writer { if (JSON_HEDLEY_UNLIKELY(j.m_data.m_value.binary->subtype() > (std::numeric_limits::max)())) { - JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(j.m_data.m_value.binary->subtype()), " is too large for the MessagePack ext type (max 255)"), &j)); + JSON_THROW(out_of_range::create(exception_id::subtype_out_of_range, concat("subtype ", std::to_string(j.m_data.m_value.binary->subtype()), " is too large for the MessagePack ext type (max 255)"), &j)); } write_number(static_cast(j.m_data.m_value.binary->subtype())); @@ -747,7 +747,7 @@ class binary_writer { if (!use_count) { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j)); } const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); const bool same_prefix = std::all_of(j.begin() + 1, j.end(), @@ -804,7 +804,7 @@ class binary_writer { if (!use_count) { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j)); } oa.write_character(to_char_type('$')); oa.write_character(bjdata_draft3 ? 'B' : 'U'); @@ -861,7 +861,7 @@ class binary_writer { if (!use_count) { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j)); } const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); const bool same_prefix = std::all_of(j.begin(), j.end(), @@ -933,7 +933,7 @@ class binary_writer { static_cast(j); // unused when JSON_NOEXCEPTION is defined static_cast(format_name); - JSON_THROW(type_error::create(321, concat("cannot serialize discarded value to ", format_name), &j)); + JSON_THROW(type_error::create(exception_id::discarded_value_used, concat("cannot serialize discarded value to ", format_name), &j)); } ////////// @@ -953,7 +953,7 @@ class binary_writer const auto it = name.find(static_cast(0)); if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) { - JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); + JSON_THROW(out_of_range::create(exception_id::bson_key_with_null, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); } string_t storage; @@ -971,7 +971,7 @@ class binary_writer { if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(size))) { - JSON_THROW(out_of_range::create(412, concat("BSON length ", std::to_string(size), " exceeds maximum of ", std::to_string((std::numeric_limits::max)())), nullptr)); + JSON_THROW(out_of_range::create(exception_id::length_too_large, concat("BSON length ", std::to_string(size), " exceeds maximum of ", std::to_string((std::numeric_limits::max)())), nullptr)); } return static_cast(size); @@ -1157,7 +1157,7 @@ class binary_writer if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits::max)())) { - JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j)); + JSON_THROW(out_of_range::create(exception_id::subtype_out_of_range, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j)); } return sizeof(std::int32_t) + value.size() + 1ul; @@ -2092,7 +2092,7 @@ class binary_writer { if (j.m_data.m_value.number_unsigned > static_cast((std::numeric_limits::max)())) { - JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BON8 as it does not fit int64"), &j)); + JSON_THROW(out_of_range::create(exception_id::integer_too_large, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BON8 as it does not fit int64"), &j)); } write_bon8_integer(static_cast(j.m_data.m_value.number_unsigned)); string_open = false; @@ -2245,7 +2245,7 @@ class binary_writer const std::size_t valid = valid_utf8_prefix(data, s.size()); if (JSON_HEDLEY_UNLIKELY(valid != s.size())) { - JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(valid), ": 0x", detail::hex_byte(data[valid])), &context)); + JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("invalid UTF-8 byte at index ", std::to_string(valid), ": 0x", detail::hex_byte(data[valid])), &context)); } } diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 8306440ef..64c4fcf03 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -888,7 +888,7 @@ class serializer { case error_handler_t::strict: { - JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", detail::hex_byte(byte)), nullptr)); + JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", detail::hex_byte(byte)), nullptr)); } case error_handler_t::ignore: @@ -1021,7 +1021,7 @@ class serializer { case error_handler_t::strict: { - JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", detail::hex_byte(static_cast(s[s.size() - 1]))), nullptr)); + JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("incomplete UTF-8 string; last byte: 0x", detail::hex_byte(static_cast(s[s.size() - 1]))), nullptr)); } case error_handler_t::ignore: diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index c81587a1c..b841e9fa3 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -639,7 +639,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec object = nullptr; // silence warning, see #821 if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(detail::exception_id::internal_error, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE } break; } @@ -2287,7 +2287,7 @@ public: // if an object is wanted but impossible, throw an exception if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) { - JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr)); + JSON_THROW(type_error::create(detail::exception_id::object_from_non_pairs, "cannot create object from initializer list", nullptr)); } } @@ -2407,7 +2407,7 @@ public: // make sure the iterator fits the current value if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterators_incompatible, "iterators are not compatible", nullptr)); } // copy type from the first iterator @@ -2426,7 +2426,7 @@ public: if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_out_of_range, "iterators out of range", first.m_object)); } break; } @@ -2494,7 +2494,7 @@ public: case value_t::null: case value_t::discarded: default: - JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_of_null, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object)); } set_parents(); @@ -2882,7 +2882,7 @@ public: return *ptr; } - JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj)); + JSON_THROW(type_error::create(detail::exception_id::incompatible_reference_type, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj)); } public: @@ -3320,7 +3320,7 @@ public: // at only works for objects if (JSON_HEDLEY_UNLIKELY(!j.is_object())) { - detail::throw_cannot_use_with(304, "at()", j); + detail::throw_cannot_use_with(detail::exception_id::at_wrong_type, "at()", j); } auto it = object_lookup(j, std::forward(key)); @@ -3330,7 +3330,7 @@ public: // std::map or ordered_map) never moves from its argument, so key is still // valid here regardless of whether KeyType was deduced as an rvalue reference // NOLINTNEXTLINE(bugprone-use-after-move,hicpp-invalid-access-moved) - JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(key), "' not found"), &j)); + JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", string_t(key), "' not found"), &j)); } return it->second; } @@ -3345,12 +3345,12 @@ public: // at only works for arrays if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { - detail::throw_cannot_use_with(304, "at()", j); + detail::throw_cannot_use_with(detail::exception_id::at_wrong_type, "at()", j); } if (JSON_HEDLEY_UNLIKELY(idx >= j.m_data.m_value.array->size())) { - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &j)); + JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), &j)); } return (*j.m_data.m_value.array)[idx]; @@ -3383,6 +3383,15 @@ public: m_data.m_type = value_t::object; } + /// @brief throws because operator[] is not supported for the type of this value + /// @param[in] argument the kind of the operator's argument, "numeric" or "string" + /// @throw type_error.305 always + JSON_HEDLEY_NO_RETURN void throw_subscript_wrong_type(const char* argument) const + { + detail::throw_cannot_use_with(detail::exception_id::subscript_wrong_type, + detail::concat("operator[] with a ", argument, " argument").c_str(), *this); + } + public: //////////////////// // element access // @@ -3487,7 +3496,7 @@ public: return m_data.m_value.array->operator[](idx); } - detail::throw_cannot_use_with(305, "operator[] with a numeric argument", *this); + throw_subscript_wrong_type("numeric"); } /// @brief access specified array element @@ -3501,7 +3510,7 @@ public: return m_data.m_value.array->operator[](idx); } - detail::throw_cannot_use_with(305, "operator[] with a numeric argument", *this); + throw_subscript_wrong_type("numeric"); } /// @brief access specified object element @@ -3521,7 +3530,7 @@ public: return set_parent(result.first->second); } - detail::throw_cannot_use_with(305, "operator[] with a string argument", *this); + throw_subscript_wrong_type("string"); } /// @brief access specified object element @@ -3536,7 +3545,7 @@ public: return it->second; } - detail::throw_cannot_use_with(305, "operator[] with a string argument", *this); + throw_subscript_wrong_type("string"); } // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC @@ -3572,7 +3581,7 @@ public: return set_parent(result.first->second); } - detail::throw_cannot_use_with(305, "operator[] with a string argument", *this); + throw_subscript_wrong_type("string"); } /// @brief access specified object element @@ -3589,7 +3598,7 @@ public: return it->second; } - detail::throw_cannot_use_with(305, "operator[] with a string argument", *this); + throw_subscript_wrong_type("string"); } private: @@ -3613,7 +3622,7 @@ public: // value only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(306, "value()", *this); + detail::throw_cannot_use_with(detail::exception_id::value_wrong_type, "value()", *this); } const auto it = find(std::forward(key)); @@ -3628,7 +3637,7 @@ public: // value only works for arrays and objects if (JSON_HEDLEY_UNLIKELY(!is_structured())) { - detail::throw_cannot_use_with(306, "value()", *this); + detail::throw_cannot_use_with(detail::exception_id::value_wrong_type, "value()", *this); } return ptr.get_checked_or_null(this); @@ -3795,7 +3804,7 @@ public: // make sure the iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } IteratorType result = end(); @@ -3811,7 +3820,7 @@ public: { if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) { - JSON_THROW(invalid_iterator::create(205, "iterator out of range", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_out_of_range, "iterator out of range", this)); } m_data.m_value.destroy(m_data.m_type); @@ -3837,7 +3846,7 @@ public: case value_t::null: case value_t::discarded: default: - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } return result; @@ -3853,7 +3862,7 @@ public: // make sure the iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) { - JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_from_other_value, "iterators do not fit current value", this)); } IteratorType result = end(); @@ -3870,7 +3879,7 @@ public: if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_out_of_range, "iterators out of range", this)); } m_data.m_value.destroy(m_data.m_type); @@ -3898,7 +3907,7 @@ public: case value_t::null: case value_t::discarded: default: - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } return result; @@ -3912,7 +3921,7 @@ public: // this erase only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } const auto erased = m_data.m_value.object->erase(std::forward(key)); @@ -3927,7 +3936,7 @@ public: // this erase only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } const auto it = object_lookup(*this, std::forward(key)); @@ -3969,14 +3978,14 @@ public: { if (JSON_HEDLEY_UNLIKELY(idx >= size())) { - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); + JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); } m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast(idx)); } else { - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } } @@ -4465,7 +4474,7 @@ public: // push_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { - detail::throw_cannot_use_with(308, "push_back()", *this); + detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this); } // transform a null object into an array @@ -4496,7 +4505,7 @@ public: // push_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { - detail::throw_cannot_use_with(308, "push_back()", *this); + detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this); } // transform a null object into an array @@ -4526,7 +4535,7 @@ public: // push_back only works for null objects or objects if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) { - detail::throw_cannot_use_with(308, "push_back()", *this); + detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this); } // transform a null object into an object @@ -4580,7 +4589,7 @@ public: // emplace_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { - detail::throw_cannot_use_with(311, "emplace_back()", *this); + detail::throw_cannot_use_with(detail::exception_id::emplace_wrong_type, "emplace_back()", *this); } // transform a null object into an array @@ -4603,7 +4612,7 @@ public: // emplace only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) { - detail::throw_cannot_use_with(311, "emplace()", *this); + detail::throw_cannot_use_with(detail::exception_id::emplace_wrong_type, "emplace()", *this); } // transform a null object into an object @@ -4655,14 +4664,14 @@ public: // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // insert to array and return iterator return insert_iterator(pos, val); } - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } /// @brief inserts element into array @@ -4675,7 +4684,7 @@ public: // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // moving into a local first keeps this safe even if val aliases @@ -4684,7 +4693,7 @@ public: return insert_iterator(pos, std::move(tmp)); } - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } /// @brief inserts copies of element into array @@ -4697,14 +4706,14 @@ public: // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // insert to array and return iterator return insert_iterator(pos, cnt, val); } - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } /// @brief inserts range of elements into array @@ -4714,30 +4723,30 @@ public: // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) { - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this)); } if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) { - JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_into_itself, "passed iterators may not belong to container", this)); } // passed iterators must belong to arrays if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_array())) { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to arrays", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterators first and last must point to arrays", this)); } // insert to array and return iterator @@ -4751,13 +4760,13 @@ public: // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) { - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // copy the values first: ilist may refer to elements of this array @@ -4779,19 +4788,19 @@ public: // insert only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this)); } // passed iterators must belong to objects if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterators first and last must point to objects", this)); } m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); @@ -4808,7 +4817,7 @@ public: // j, not the copy made below) if (JSON_HEDLEY_UNLIKELY(!j.is_object())) { - detail::throw_cannot_use_with(312, "update()", j); + detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", j); } // copy first: j may be *this or one of its descendants, and is @@ -4826,13 +4835,13 @@ public: // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this)); } // passed iterators must belong to objects if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) { - detail::throw_cannot_use_with(312, "update()", *first.m_object); + detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", *first.m_object); } // copy first: the range may belong to *this or one of its @@ -4868,7 +4877,7 @@ public: if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(312, "update()", *this); + detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", *this); } } @@ -5031,7 +5040,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(array_t&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(array_t&)", *this); } } @@ -5048,7 +5057,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(object_t&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(object_t&)", *this); } } @@ -5064,7 +5073,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(string_t&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(string_t&)", *this); } } @@ -5080,7 +5089,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(binary_t&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(binary_t&)", *this); } } @@ -5096,7 +5105,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(binary_t::container_type&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(binary_t::container_type&)", *this); } } @@ -6558,7 +6567,7 @@ public: if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) { // avoid undefined behavior - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent)); + JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent)); } // default case: insert add offset @@ -6577,7 +6586,7 @@ public: case value_t::binary: case value_t::discarded: default: - JSON_THROW(out_of_range::create(411, detail::concat("cannot add value: the JSON Patch 'add' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent)); + JSON_THROW(out_of_range::create(detail::exception_id::patch_add_parent_not_container, detail::concat("cannot add value: the JSON Patch 'add' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent)); } }; @@ -6600,7 +6609,7 @@ public: } else { - JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this)); + JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", last_path, "' not found"), this)); } } else if (parent.is_array()) @@ -6612,7 +6621,7 @@ public: { // the parent of a "remove" target must be an object or array // (see #5396) - JSON_THROW(out_of_range::create(413, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent)); + JSON_THROW(out_of_range::create(detail::exception_id::patch_remove_parent_not_container, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent)); } }; @@ -6643,7 +6652,7 @@ public: // type check: top level value must be an array if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch)); + JSON_THROW(parse_error::create(detail::exception_id::patch_not_an_array, 0, "JSON patch must be an array of objects", &json_patch)); } // iterate and apply the operations @@ -6664,14 +6673,14 @@ public: if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val)); + JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat(error_msg, " must have member '", member, "'"), &val)); } // check if the result is of type string if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val)); + JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val)); } // no error: return value @@ -6681,7 +6690,7 @@ public: // type check: every element of the array must be an object if (JSON_HEDLEY_UNLIKELY(!val.is_object())) { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val)); + JSON_THROW(parse_error::create(detail::exception_id::patch_not_an_array, 0, "JSON patch must be an array of objects", &val)); } // collect mandatory members @@ -6717,7 +6726,7 @@ public: if (JSON_HEDLEY_UNLIKELY(is_proper_prefix(from_ptr, ptr))) { - JSON_THROW(out_of_range::create(414, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result)); + JSON_THROW(out_of_range::create(detail::exception_id::patch_move_into_child, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result)); } // the "from" location must exist - use at() @@ -6764,7 +6773,7 @@ public: // throw an exception if the test fails if (JSON_HEDLEY_UNLIKELY(!success)) { - JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val)); + JSON_THROW(other_error::create(detail::exception_id::patch_test_failed, detail::concat("unsuccessful: ", val.dump()), &val)); } break; @@ -6775,7 +6784,7 @@ public: { // op must be "add", "remove", "replace", "move", "copy", or // "test" - JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val)); + JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat("operation value '", op, "' is invalid"), &val)); } } } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index a274253da..73175c44b 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2649,7 +2649,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP return ej_pair.first == e; \ }); \ if (it != std::end(m)) j = it->second; \ - else ::nlohmann::detail::templated_json_throw(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE, nullptr)); \ + else ::nlohmann::detail::templated_json_throw(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range,"enum value out of range for " #ENUM_TYPE, nullptr)); \ } \ template \ inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ @@ -2664,7 +2664,7 @@ JSON_HEDLEY_DIAGNOSTIC_POP return ej_pair.second == j; \ }); \ if (it != std::end(m)) e = it->first; \ - else ::nlohmann::detail::templated_json_throw(nlohmann::detail::out_of_range::create(410, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \ + else ::nlohmann::detail::templated_json_throw(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \ } // Ugly macros to avoid uglier copy-paste when specializing basic_json. They @@ -5237,6 +5237,84 @@ namespace detail // exceptions // //////////////// +/*! +@brief the ids of the exceptions thrown by the library +@note The values are part of the public API: they are the `id` member of the + exceptions and appear in their `what()` messages. +@sa https://json.nlohmann.me/home/exceptions/ +*/ +enum class exception_id : int +{ + // parse_error + syntax_error = 101, ///< unexpected token or invalid literal while parsing JSON + patch_not_an_array = 104, ///< a JSON Patch document is not an array of objects + patch_invalid_operation = 105, ///< a JSON Patch operation is malformed + pointer_index_leading_zero = 106, ///< a JSON Pointer array index has a leading zero + pointer_missing_slash = 107, ///< a JSON Pointer does not start with '/' + pointer_invalid_escape = 108, ///< a JSON Pointer contains an escape other than ~0 and ~1 + pointer_index_not_a_number = 109, ///< a JSON Pointer array index is not a number + unexpected_end_of_input = 110, ///< a binary input ends early, or has bytes left at its end + unexpected_byte = 112, ///< a binary input contains an unexpected byte or invalid length + invalid_string_or_size = 113, ///< a binary input contains an invalid string or size specification + bson_unsupported_type = 114, ///< a BSON record type is not supported + invalid_high_precision_number = 115, ///< a UBJSON/BJData high-precision number cannot be parsed + // invalid_iterator + iterators_incompatible = 201, ///< the iterators of a range belong to different values + iterator_from_other_value = 202, ///< an iterator does not belong to the value it is used with + iterator_range_from_other_value = 203, ///< an iterator range does not belong to the value it is used with + iterator_range_out_of_range = 204, ///< an iterator range of a primitive value is not [begin, end) + iterator_out_of_range = 205, ///< an iterator of a primitive value is not begin() + iterator_range_of_null = 206, ///< an iterator range belongs to a null value + iterator_key_not_object = 207, ///< key() is called on an iterator of a non-object + iterator_subscript_on_object = 208, ///< operator[] is called on an iterator of an object + iterator_arithmetic_on_object = 209, ///< an offset operator is used on an iterator of an object + insert_range_incompatible = 210, ///< the iterators of an inserted range belong to different values + insert_range_into_itself = 211, ///< an inserted range belongs to the value it is inserted into + iterators_compare_different_values = 212, ///< iterators of different values are compared + iterator_order_on_object = 213, ///< iterators of an object are compared by order + iterator_value_unavailable = 214, ///< an iterator does not refer to a value + // type_error + object_from_non_pairs = 301, ///< an object is created from an initializer list that is not a list of pairs + type_mismatch = 302, ///< a value has the wrong type for a conversion + incompatible_reference_type = 303, ///< get_ref() is called with a reference type that does not match the value + at_wrong_type = 304, ///< at() is called on a value of the wrong type + subscript_wrong_type = 305, ///< operator[] is called on a value of the wrong type + value_wrong_type = 306, ///< value() is called on a value of the wrong type + erase_wrong_type = 307, ///< erase() is called on a value of the wrong type + push_back_wrong_type = 308, ///< push_back() or operator+= is called on a value of the wrong type + insert_wrong_type = 309, ///< insert() is called on a value of the wrong type + swap_wrong_type = 310, ///< swap() is called on a value of the wrong type + emplace_wrong_type = 311, ///< emplace() or emplace_back() is called on a value of the wrong type + update_wrong_type = 312, ///< update() is called on a value of the wrong type + unflatten_invalid_value = 313, ///< unflatten() finds conflicting paths + unflatten_not_object = 314, ///< unflatten() is called on a non-object + unflatten_value_not_primitive = 315, ///< unflatten() is called on an object with non-primitive values + invalid_utf8 = 316, ///< dump() finds a string that is not valid UTF-8 + type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format + enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string + discarded_value_used = 321, ///< a discarded value is used + // out_of_range + array_index_out_of_range = 401, ///< an array index is out of range + pointer_past_the_end_index = 402, ///< a JSON Pointer uses the array index '-' + key_not_found = 403, ///< an object key is not found + pointer_unresolved = 404, ///< a JSON Pointer reference token cannot be resolved + patch_on_root = 405, ///< the root of a value has no parent, e.g. for a JSON Patch 'remove' or 'add' at the root + number_overflow = 406, ///< a number cannot be stored without overflowing to NaN or INF + integer_too_large = 407, ///< an integer cannot be represented in the binary format + container_too_large = 408, ///< the size of a container in a binary input exceeds the maximal capacity + bson_key_with_null = 409, ///< a BSON key contains U+0000 + value_out_of_range = 410, ///< an enum value is undefined, or a JSON Pointer array index exceeds size_type + patch_add_parent_not_container = 411, ///< the parent of a JSON Patch 'add' target is not a container + length_too_large = 412, ///< a length does not fit into the length field of a binary format + patch_remove_parent_not_container = 413, ///< the parent of a JSON Patch 'remove' target is not a container + patch_move_into_child = 414, ///< a JSON Patch 'move' moves a value into one of its children + subtype_out_of_range = 415, ///< a binary subtype does not fit into one byte + // other_error + internal_error = 500, ///< unreachable code was reached + patch_test_failed = 501, ///< a JSON Patch 'test' operation failed + size_marker_required = 502 ///< UBJSON/BJData output with type markers requires size markers +}; + /// @brief general exception of the @ref basic_json class /// @sa https://json.nlohmann.me/api/basic_json/exception/ class exception : public std::exception @@ -5387,6 +5465,18 @@ class parse_error : public exception return {id_, byte_, w.c_str()}; } + template::value, int> = 0> + static parse_error create(exception_id id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), pos, what_arg, context); + } + + template::value, int> = 0> + static parse_error create(exception_id id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), byte_, what_arg, context); + } + /*! @brief byte index of the parse error @@ -5421,6 +5511,12 @@ class invalid_iterator : public exception return {id_, w.c_str()}; } + template::value, int> = 0> + static invalid_iterator create(exception_id id_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), what_arg, context); + } + private: JSON_HEDLEY_NON_NULL(3) invalid_iterator(int id_, const char* what_arg) @@ -5439,6 +5535,12 @@ class type_error : public exception return {id_, w.c_str()}; } + template::value, int> = 0> + static type_error create(exception_id id_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), what_arg, context); + } + private: JSON_HEDLEY_NON_NULL(3) type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} @@ -5456,6 +5558,12 @@ class out_of_range : public exception return {id_, w.c_str()}; } + template::value, int> = 0> + static out_of_range create(exception_id id_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), what_arg, context); + } + private: JSON_HEDLEY_NON_NULL(3) out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} @@ -5473,6 +5581,12 @@ class other_error : public exception return {id_, w.c_str()}; } + template::value, int> = 0> + static other_error create(exception_id id_, const std::string& what_arg, BasicJsonContext context) + { + return create(static_cast(id_), what_arg, context); + } + private: JSON_HEDLEY_NON_NULL(3) other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} @@ -5510,18 +5624,18 @@ JSON_HEDLEY_NO_RETURN inline void throw_type_must_be(const char* expected, const { static_cast(expected); // unused when JSON_NOEXCEPTION is defined static_cast(j); - JSON_THROW(type_error::create(302, concat("type must be ", expected, ", but is ", j.type_name()), &j)); + JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), &j)); } /*! @brief throws because an operation is not supported for the type of @a j -@param[in] id_ the id of the type_error exception (304..312) +@param[in] id_ the id of the type_error exception (at_wrong_type..update_wrong_type) @param[in] operation the operation, e.g. "erase()" @param[in] j the value the operation was called on @throw type_error always */ template -JSON_HEDLEY_NO_RETURN inline void throw_cannot_use_with(const int id_, const char* operation, const BasicJsonType& j) +JSON_HEDLEY_NO_RETURN inline void throw_cannot_use_with(const exception_id id_, const char* operation, const BasicJsonType& j) { static_cast(id_); // unused when JSON_NOEXCEPTION is defined static_cast(operation); @@ -7244,7 +7358,7 @@ inline void to_json(BasicJsonType& j, const EnumKeyedMap& map) auto& key_string = *key.template get_ptr(); if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second)) { - JSON_THROW(type_error::create(318, concat("duplicate object key '", key_string, "'"), &key)); + JSON_THROW(type_error::create(exception_id::enum_key_duplicate, concat("duplicate object key '", key_string, "'"), &key)); } } external_constructor::construct(j, std::move(obj)); @@ -8420,7 +8534,7 @@ class wide_string_input_adapter template JSON_HEDLEY_NO_RETURN std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1) { - JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr)); + JSON_THROW(parse_error::create(exception_id::unexpected_byte, 1, "wide string type cannot be interpreted as binary data", nullptr)); } private: @@ -8632,7 +8746,7 @@ inline file_input_adapter input_adapter(std::FILE* file) { if (file == nullptr) { - JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); } return file_input_adapter(file); } @@ -8641,7 +8755,7 @@ inline input_stream_adapter input_adapter(std::istream& stream) { if (stream.rdbuf() == nullptr) { - JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); } return input_stream_adapter(stream); } @@ -8666,7 +8780,7 @@ contiguous_bytes_input_adapter input_adapter(CharT b) { if (b == nullptr) { - JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); } auto length = std::strlen(reinterpret_cast(b)); const auto* ptr = reinterpret_cast(b); @@ -12636,7 +12750,7 @@ bool check_container_size(SAX& sax, std::size_t len, const char* kind, BasicJson { if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref->max_size())) { - return sax.parse_error(0, "", out_of_range::create(408, concat("excessive ", kind, " size: ", std::to_string(len)), ref)); + return sax.parse_error(0, "", out_of_range::create(exception_id::container_too_large, concat("excessive ", kind, " size: ", std::to_string(len)), ref)); } return true; } @@ -13928,7 +14042,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(current != char_traits::eof())) { - return last_byte_error(110, concat("expected end of input; last byte: 0x", get_token_string()), "value"); + return last_byte_error(exception_id::unexpected_end_of_input, concat("expected end of input; last byte: 0x", get_token_string()), "value"); } } @@ -14050,7 +14164,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast(document_size) != chars_read - document_start)) { - return last_byte_error(112, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"); + return last_byte_error(exception_id::unexpected_byte, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"); } return true; } @@ -14242,7 +14356,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(len < 1)) { - return last_byte_error(112, concat("string length must be at least 1, is ", std::to_string(len)), "string"); + return last_byte_error(exception_id::unexpected_byte, concat("string length must be at least 1, is ", std::to_string(len)), "string"); } if (JSON_HEDLEY_UNLIKELY(!get_string(len - static_cast(1), result))) @@ -14252,7 +14366,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(get() != 0x00)) { - return last_byte_error(112, "BSON string is not null-terminated", "string"); + return last_byte_error(exception_id::unexpected_byte, "BSON string is not null-terminated", "string"); } return check_string_utf8(result, "string"); @@ -14272,7 +14386,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(len < 0)) { - return last_byte_error(112, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"); + return last_byte_error(exception_id::unexpected_byte, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"); } // All BSON binary values have a subtype @@ -14364,7 +14478,7 @@ class binary_reader { const std::string cr_str = hex_byte(static_cast(element_type)); return sax->parse_error(element_type_parse_position, cr_str, - parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)); + parse_error::create(exception_id::bson_unsupported_type, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr)); } } } @@ -14688,7 +14802,7 @@ class binary_reader { if (tag_handler == cbor_tag_handler_t::error) { - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } // ignore and store: the tag value is already in the head, so @@ -14708,7 +14822,7 @@ class binary_reader { case cbor_tag_handler_t::error: { - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } case cbor_tag_handler_t::ignore: @@ -14782,7 +14896,7 @@ class binary_reader default: // anything else (0xFF is handled inside the other types) { - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } } } @@ -14795,7 +14909,7 @@ class binary_reader */ bool cbor_indefinite_string_error(const char* type_name, const char* context) { - return last_byte_error(113, concat("indefinite-length ", type_name, " is not allowed inside indefinite-length ", type_name, "; last byte: 0x", get_token_string()), context); + return last_byte_error(exception_id::invalid_string_or_size, concat("indefinite-length ", type_name, " is not allowed inside indefinite-length ", type_name, "; last byte: 0x", get_token_string()), context); } /*! @@ -14872,7 +14986,7 @@ class binary_reader default: { - return last_byte_error(113, concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", get_token_string()), "string"); + return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", get_token_string()), "string"); } } } @@ -15002,7 +15116,7 @@ class binary_reader break; } - return last_byte_error(113, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key"); + return last_byte_error(exception_id::invalid_string_or_size, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key"); } /*! @@ -15083,7 +15197,7 @@ class binary_reader default: { - return last_byte_error(113, concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", get_token_string()), "binary"); + return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", get_token_string()), "binary"); } } } @@ -15229,7 +15343,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(len) || len == detail::unknown_size())) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message(concat("excessive ", context, " size"), "size"), nullptr)); } result = conditional_static_cast(len); @@ -15717,7 +15831,7 @@ class binary_reader default: // anything else { - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } } } @@ -15798,7 +15912,7 @@ class binary_reader default: { - return last_byte_error(113, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", get_token_string()), "string"); + return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", get_token_string()), "string"); } } } @@ -15890,7 +16004,7 @@ class binary_reader break; } - return last_byte_error(113, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key"); + return last_byte_error(exception_id::invalid_string_or_size, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key"); } /*! @@ -16199,7 +16313,7 @@ class binary_reader { if (JSON_HEDLEY_UNLIKELY(len < 0)) { - return last_byte_error(113, "string length must not be negative", "string"); + return last_byte_error(exception_id::invalid_string_or_size, "string length must not be negative", "string"); } return true; } @@ -16299,10 +16413,7 @@ class binary_reader default: break; } - const char* expected = input_format != input_format_t::bjdata - ? "expected length type specification (U, i, I, l, L)" - : "expected length type specification (U, i, u, I, m, l, M, L)"; - return last_byte_error(113, concat(expected, "; last byte: 0x", get_token_string()), "string"); + return length_type_error("", "string"); } /*! @@ -16387,11 +16498,11 @@ class binary_reader } if (JSON_HEDLEY_UNLIKELY(number < 0)) { - return last_byte_error(113, "count in an optimized container must be positive", "size"); + return last_byte_error(exception_id::invalid_string_or_size, "count in an optimized container must be positive", "size"); } if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(number))) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("integer value overflow", "size"), nullptr)); } result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char @@ -16484,7 +16595,7 @@ class binary_reader } if (!value_in_range_of(number)) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("integer value overflow", "size"), nullptr)); } result = detail::conditional_static_cast(number); @@ -16499,7 +16610,7 @@ class binary_reader } if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array { - return last_byte_error(113, "ndarray dimensional vector is not allowed", "size"); + return last_byte_error(exception_id::invalid_string_or_size, "ndarray dimensional vector is not allowed", "size"); } std::vector dim; if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim))) @@ -16539,7 +16650,7 @@ class binary_reader // or SIZE_MAX. if (JSON_HEDLEY_UNLIKELY(result > (std::numeric_limits::max)() / i)) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); } result *= i; // the pre-check above already rules out result becoming 0 @@ -16548,7 +16659,7 @@ class binary_reader // unknown-size container (see get_ubjson_size_type()) if (result == npos) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive ndarray size caused overflow", "size"), nullptr)); } if (JSON_HEDLEY_UNLIKELY(!emit_unsigned(i))) { @@ -16565,10 +16676,7 @@ class binary_reader default: break; } - const char* expected = input_format != input_format_t::bjdata - ? "expected length type specification (U, i, I, l, L) after '#'" - : "expected length type specification (U, i, u, I, m, l, M, L) after '#'"; - return last_byte_error(113, concat(expected, "; last byte: 0x", get_token_string()), "size"); + return length_type_error(" after '#'", "size"); } /*! @@ -16601,7 +16709,7 @@ class binary_reader if (input_format == input_format_t::bjdata && JSON_HEDLEY_UNLIKELY(is_bjd_excluded_optimized_type(result.second))) { - return last_byte_error(112, concat("marker 0x", get_token_string(), " is not a permitted optimized array type"), "type"); + return last_byte_error(exception_id::unexpected_byte, concat("marker 0x", get_token_string(), " is not a permitted optimized array type"), "type"); } if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type"))) @@ -16616,7 +16724,7 @@ class binary_reader { return false; } - return last_byte_error(112, concat("expected '#' after type information; last byte: 0x", get_token_string()), "size"); + return last_byte_error(exception_id::unexpected_byte, concat("expected '#' after type information; last byte: 0x", get_token_string()), "size"); } const bool is_error = get_ubjson_size_value(result.first, is_ndarray); @@ -16635,7 +16743,7 @@ class binary_reader const bool is_error = get_ubjson_size_value(result.first, is_ndarray); if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray) { - return last_byte_error(112, "ndarray requires both type and size", "size"); + return last_byte_error(exception_id::unexpected_byte, "ndarray requires both type and size", "size"); } return is_error; } @@ -16767,7 +16875,7 @@ class binary_reader } if (JSON_HEDLEY_UNLIKELY(current > 127)) { - return last_byte_error(113, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", get_token_string()), "char"); + return last_byte_error(exception_id::invalid_string_or_size, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", get_token_string()), "char"); } string_t s(1, static_cast(current)); return sax->string(s); @@ -16788,7 +16896,7 @@ class binary_reader default: // anything else break; } - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } /*! @@ -16812,7 +16920,7 @@ class binary_reader string_t key = "_ArrayType_"; if (JSON_HEDLEY_UNLIKELY(type_name == nullptr)) { - return unexpected_byte("invalid byte", "type"); + return invalid_byte("type"); } string_t type = type_name; // sax->string() takes a reference @@ -16859,7 +16967,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY((size_and_type.second == 'Z' || size_and_type.second == 'T' || size_and_type.second == 'F') && size_and_type.first > max_valueless_container_size)) { - return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, + return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive array size", "size"), nullptr)); } @@ -16895,7 +17003,7 @@ class binary_reader // do not accept ND-array size in objects in BJData if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0) { - return last_byte_error(112, "BJData object does not support ND-array size in optimized format", "object"); + return last_byte_error(exception_id::unexpected_byte, "BJData object does not support ND-array size in optimized format", "object"); } if (size_and_type.first != npos) @@ -16932,7 +17040,7 @@ class binary_reader // the lexer would stop at a NUL and accept the digits before it if (JSON_HEDLEY_UNLIKELY(current == '\0')) { - return sax->parse_error(chars_read, "00", parse_error::create(115, chars_read, + return sax->parse_error(chars_read, "00", parse_error::create(exception_id::invalid_high_precision_number, chars_read, exception_message("invalid number text; last byte: 0x00", "high-precision number"), nullptr)); } number_vector.push_back(static_cast(current)); @@ -16949,7 +17057,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) { - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + return sax->parse_error(chars_read, number_string, parse_error::create(exception_id::invalid_high_precision_number, chars_read, exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); } @@ -16967,7 +17075,7 @@ class binary_reader return sax->parse_error( chars_read, number_string, - out_of_range::create(406, concat("number overflow parsing '", number_string, '\''), nullptr)); + out_of_range::create(exception_id::number_overflow, concat("number overflow parsing '", number_string, '\''), nullptr)); } // number_string is a std::string, while the SAX interface takes a // string_t; convert explicitly, as the two are only implicitly @@ -16989,7 +17097,7 @@ class binary_reader case token_type::end_of_input: case token_type::literal_or_value: default: - return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, + return sax->parse_error(chars_read, number_string, parse_error::create(exception_id::invalid_high_precision_number, chars_read, exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr)); } } @@ -17263,7 +17371,7 @@ class binary_reader } // 0xFE: end of container where a value is expected - return unexpected_byte("invalid byte", "value"); + return invalid_byte("value"); } /*! @@ -17572,7 +17680,7 @@ class binary_reader { // in case of failure, advance position by 1 to report the failing location ++chars_read; - sax->parse_error(chars_read, "", parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr)); + sax->parse_error(chars_read, "", parse_error::create(exception_id::unexpected_end_of_input, chars_read, exception_message("unexpected end of input", context), nullptr)); return false; } return true; @@ -17726,7 +17834,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(std::isfinite(number) && !std::isfinite(result))) { return sax->parse_error(chars_read, get_token_string(), - out_of_range::create(406, exception_message("number overflow", "value"), nullptr)); + out_of_range::create(exception_id::number_overflow, exception_message("number overflow", "value"), nullptr)); } return sax->number_float(result, ""); } @@ -17846,7 +17954,7 @@ class binary_reader if (error_handler == error_handler_t::strict) { - return last_byte_error(113, "invalid string: ill-formed UTF-8 byte", context); + return last_byte_error(exception_id::invalid_string_or_size, "invalid string: ill-formed UTF-8 byte", context); } result = sanitize_utf8(result, error_handler); @@ -17942,7 +18050,7 @@ class binary_reader if (JSON_HEDLEY_UNLIKELY(current == char_traits::eof())) { return sax->parse_error(chars_read, "", - parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr)); + parse_error::create(exception_id::unexpected_end_of_input, chars_read, exception_message("unexpected end of input", context), nullptr)); } return true; } @@ -17954,7 +18062,7 @@ class binary_reader @param[in] context further context information @return the result of the SAX parser's parse_error() */ - bool last_byte_error(const int id_, const std::string& detail, const std::string& context) const + bool last_byte_error(const exception_id id_, const std::string& detail, const std::string& context) const { return sax->parse_error(chars_read, get_token_string(), parse_error::create(id_, chars_read, exception_message(detail, context), nullptr)); } @@ -17967,7 +18075,30 @@ class binary_reader */ bool unexpected_byte(const char* detail, const std::string& context) const { - return last_byte_error(112, concat(detail, ": 0x", get_token_string()), context); + return last_byte_error(exception_id::unexpected_byte, concat(detail, ": 0x", get_token_string()), context); + } + + /*! + @brief reports the last read byte as invalid (parse_error.112) + @param[in] context further context information + @return the result of the SAX parser's parse_error() + */ + bool invalid_byte(const char* context) const + { + return unexpected_byte("invalid byte", context); + } + + /*! + @brief reports that the last read byte is not a UBJSON/BJData length type (parse_error.113) + @param[in] position where the length type was expected, e.g. " after '#'" + @param[in] context further context information + @return the result of the SAX parser's parse_error() + */ + bool length_type_error(const char* position, const char* context) const + { + const char* types = input_format == input_format_t::bjdata ? "U, i, u, I, m, l, M, L" : "U, i, I, l, L"; + return last_byte_error(exception_id::invalid_string_or_size, + concat("expected length type specification (", types, ")", position, "; last byte: 0x", get_token_string()), context); } /*! @@ -18434,7 +18565,7 @@ class parser { return sax->parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); + out_of_range::create(exception_id::number_overflow, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr)); } if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) @@ -18655,7 +18786,7 @@ class parser bool syntax_error(SAX& sax, const std::string& message) { return sax.parse_error(m_lexer.get_position(), m_lexer.get_token_string(), - parse_error::create(101, m_lexer.get_position(), message, nullptr)); + parse_error::create(exception_id::syntax_error, m_lexer.get_position(), message, nullptr)); } std::string exception_message(const token_type expected, const std::string& context) @@ -19167,7 +19298,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci /// @throw invalid_iterator.214 always JSON_HEDLEY_NO_RETURN void throw_cannot_get_value() const { - JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_value_unavailable, "cannot get value", m_object)); } public: @@ -19369,7 +19500,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci // if objects are not the same, the comparison is undefined if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object)); } // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 @@ -19418,7 +19549,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci // if objects are not the same, the comparison is undefined if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object)); } // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493 @@ -19431,7 +19562,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci switch (m_object->m_data.m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_order_on_object, "cannot compare order of object iterators", m_object)); case value_t::array: return (m_it.array_iterator < other.m_it.array_iterator); @@ -19487,7 +19618,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci switch (m_object->m_data.m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object)); case value_t::array: { @@ -19566,7 +19697,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci switch (m_object->m_data.m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object)); case value_t::array: return m_it.array_iterator - other.m_it.array_iterator; @@ -19595,7 +19726,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci switch (m_object->m_data.m_type) { case value_t::object: - JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_subscript_on_object, "cannot use operator[] for object iterators", m_object)); case value_t::array: return *std::next(m_it.array_iterator, n); @@ -19635,7 +19766,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci return m_it.object_iterator->first; } - JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object)); + JSON_THROW(invalid_iterator::create(exception_id::iterator_key_not_object, "cannot use key() for non-object iterators", m_object)); } /*! @@ -20104,7 +20235,7 @@ class json_pointer /// @throw out_of_range.405 always JSON_HEDLEY_NO_RETURN static void throw_no_parent() { - JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr)); + JSON_THROW(detail::out_of_range::create(detail::exception_id::patch_on_root, "JSON pointer has no parent", nullptr)); } /// @throw out_of_range.404 always @@ -20113,7 +20244,7 @@ class json_pointer { static_cast(reference_token); // unused when JSON_NOEXCEPTION is defined static_cast(context); - JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), context)); + JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_unresolved, detail::concat("unresolved reference token '", reference_token, "'"), context)); } /*! @@ -20201,13 +20332,13 @@ class json_pointer // the branches differ in their messages, not after JSON_THROW's expansion // NOLINTNEXTLINE(bugprone-branch-clone) case array_index_status::leading_zero: - JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_leading_zero, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr)); case array_index_status::not_a_number: - JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_not_a_number, 0, detail::concat("array index '", s, "' is not a number"), nullptr)); case array_index_status::unresolved: throw_unresolved(s, nullptr); case array_index_status::exceeds_size_type: - JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); + JSON_THROW(detail::out_of_range::create(detail::exception_id::value_out_of_range, detail::concat("array index ", s, " exceeds size_type"), nullptr)); case array_index_status::ok: default: break; @@ -20309,7 +20440,7 @@ class json_pointer case detail::value_t::binary: case detail::value_t::discarded: default: - JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j)); + JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_invalid_value, "invalid value to unflatten", &j)); } prefix.push_back(reference_token); @@ -20424,7 +20555,7 @@ class json_pointer if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" always fails the range check - JSON_THROW(detail::out_of_range::create(402, detail::concat( + JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_past_the_end_index, detail::concat( "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } @@ -20433,7 +20564,7 @@ class json_pointer // Bounds check before access to avoid exception with JSON_NOEXCEPTION if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size())) { - JSON_THROW(detail::out_of_range::create(401, detail::concat( + JSON_THROW(detail::out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat( "array index ", std::to_string(idx), " is out of range"), ptr)); } ptr = &ptr->operator[](idx); @@ -20493,7 +20624,7 @@ class json_pointer if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) { // "-" cannot be used for const access - JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); + JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_past_the_end_index, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr)); } // use unchecked array access; the const operator[] @@ -20566,9 +20697,9 @@ class json_pointer // the branches differ in their messages, not after JSON_THROW's expansion // NOLINTNEXTLINE(bugprone-branch-clone) case array_index_status::leading_zero: - JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_leading_zero, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr)); case array_index_status::not_a_number: - JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", reference_token, "' is not a number"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_not_a_number, 0, detail::concat("array index '", reference_token, "' is not a number"), nullptr)); case array_index_status::unresolved: case array_index_status::exceeds_size_type: return nullptr; @@ -20695,7 +20826,7 @@ class json_pointer // check if a nonempty reference string begins with slash if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) { - JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_missing_slash, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr)); } // extract the reference tokens: @@ -20731,7 +20862,7 @@ class json_pointer (reference_token[pos + 1] != '0' && reference_token[pos + 1] != '1'))) { - JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); + JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_invalid_escape, 0, "escape character '~' must be followed with '0' or '1'", nullptr)); } } @@ -20828,7 +20959,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(!value.is_object())) { - JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value)); + JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_not_object, "only objects can be unflattened", &value)); } BasicJsonType result; @@ -20856,7 +20987,7 @@ class json_pointer { if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) { - JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second)); + JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_value_not_primitive, "values in object must be primitive", &element.second)); } // Assign the value to the reference pointed to by JSON pointer. Note @@ -21608,7 +21739,7 @@ class binary_writer case value_t::discarded: default: { - JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j)); + JSON_THROW(type_error::create(exception_id::type_not_serializable, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j)); } } } @@ -21796,7 +21927,7 @@ class binary_writer { if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(length))) { - JSON_THROW(out_of_range::create(412, concat("MessagePack length ", std::to_string(length), " exceeds maximum of ", std::to_string((std::numeric_limits::max)())), &j)); + JSON_THROW(out_of_range::create(exception_id::length_too_large, concat("MessagePack length ", std::to_string(length), " exceeds maximum of ", std::to_string((std::numeric_limits::max)())), &j)); } static_cast(j); @@ -22062,7 +22193,7 @@ class binary_writer { if (JSON_HEDLEY_UNLIKELY(j.m_data.m_value.binary->subtype() > (std::numeric_limits::max)())) { - JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(j.m_data.m_value.binary->subtype()), " is too large for the MessagePack ext type (max 255)"), &j)); + JSON_THROW(out_of_range::create(exception_id::subtype_out_of_range, concat("subtype ", std::to_string(j.m_data.m_value.binary->subtype()), " is too large for the MessagePack ext type (max 255)"), &j)); } write_number(static_cast(j.m_data.m_value.binary->subtype())); @@ -22205,7 +22336,7 @@ class binary_writer { if (!use_count) { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j)); } const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); const bool same_prefix = std::all_of(j.begin() + 1, j.end(), @@ -22262,7 +22393,7 @@ class binary_writer { if (!use_count) { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j)); } oa.write_character(to_char_type('$')); oa.write_character(bjdata_draft3 ? 'B' : 'U'); @@ -22319,7 +22450,7 @@ class binary_writer { if (!use_count) { - JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j)); + JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j)); } const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); const bool same_prefix = std::all_of(j.begin(), j.end(), @@ -22391,7 +22522,7 @@ class binary_writer { static_cast(j); // unused when JSON_NOEXCEPTION is defined static_cast(format_name); - JSON_THROW(type_error::create(321, concat("cannot serialize discarded value to ", format_name), &j)); + JSON_THROW(type_error::create(exception_id::discarded_value_used, concat("cannot serialize discarded value to ", format_name), &j)); } ////////// @@ -22411,7 +22542,7 @@ class binary_writer const auto it = name.find(static_cast(0)); if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) { - JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); + JSON_THROW(out_of_range::create(exception_id::bson_key_with_null, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j)); } string_t storage; @@ -22429,7 +22560,7 @@ class binary_writer { if (JSON_HEDLEY_UNLIKELY(!value_in_range_of(size))) { - JSON_THROW(out_of_range::create(412, concat("BSON length ", std::to_string(size), " exceeds maximum of ", std::to_string((std::numeric_limits::max)())), nullptr)); + JSON_THROW(out_of_range::create(exception_id::length_too_large, concat("BSON length ", std::to_string(size), " exceeds maximum of ", std::to_string((std::numeric_limits::max)())), nullptr)); } return static_cast(size); @@ -22615,7 +22746,7 @@ class binary_writer if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits::max)())) { - JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j)); + JSON_THROW(out_of_range::create(exception_id::subtype_out_of_range, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j)); } return sizeof(std::int32_t) + value.size() + 1ul; @@ -23550,7 +23681,7 @@ class binary_writer { if (j.m_data.m_value.number_unsigned > static_cast((std::numeric_limits::max)())) { - JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BON8 as it does not fit int64"), &j)); + JSON_THROW(out_of_range::create(exception_id::integer_too_large, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BON8 as it does not fit int64"), &j)); } write_bon8_integer(static_cast(j.m_data.m_value.number_unsigned)); string_open = false; @@ -23703,7 +23834,7 @@ class binary_writer const std::size_t valid = valid_utf8_prefix(data, s.size()); if (JSON_HEDLEY_UNLIKELY(valid != s.size())) { - JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(valid), ": 0x", detail::hex_byte(data[valid])), &context)); + JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("invalid UTF-8 byte at index ", std::to_string(valid), ": 0x", detail::hex_byte(data[valid])), &context)); } } @@ -26118,7 +26249,7 @@ class serializer { case error_handler_t::strict: { - JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", detail::hex_byte(byte)), nullptr)); + JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", detail::hex_byte(byte)), nullptr)); } case error_handler_t::ignore: @@ -26251,7 +26382,7 @@ class serializer { case error_handler_t::strict: { - JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", detail::hex_byte(static_cast(s[s.size() - 1]))), nullptr)); + JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("incomplete UTF-8 string; last byte: 0x", detail::hex_byte(static_cast(s[s.size() - 1]))), nullptr)); } case error_handler_t::ignore: @@ -27835,7 +27966,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec object = nullptr; // silence warning, see #821 if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(detail::exception_id::internal_error, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE } break; } @@ -29483,7 +29614,7 @@ public: // if an object is wanted but impossible, throw an exception if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) { - JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr)); + JSON_THROW(type_error::create(detail::exception_id::object_from_non_pairs, "cannot create object from initializer list", nullptr)); } } @@ -29603,7 +29734,7 @@ public: // make sure the iterator fits the current value if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterators_incompatible, "iterators are not compatible", nullptr)); } // copy type from the first iterator @@ -29622,7 +29753,7 @@ public: if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_out_of_range, "iterators out of range", first.m_object)); } break; } @@ -29690,7 +29821,7 @@ public: case value_t::null: case value_t::discarded: default: - JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_of_null, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object)); } set_parents(); @@ -30078,7 +30209,7 @@ public: return *ptr; } - JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj)); + JSON_THROW(type_error::create(detail::exception_id::incompatible_reference_type, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj)); } public: @@ -30516,7 +30647,7 @@ public: // at only works for objects if (JSON_HEDLEY_UNLIKELY(!j.is_object())) { - detail::throw_cannot_use_with(304, "at()", j); + detail::throw_cannot_use_with(detail::exception_id::at_wrong_type, "at()", j); } auto it = object_lookup(j, std::forward(key)); @@ -30526,7 +30657,7 @@ public: // std::map or ordered_map) never moves from its argument, so key is still // valid here regardless of whether KeyType was deduced as an rvalue reference // NOLINTNEXTLINE(bugprone-use-after-move,hicpp-invalid-access-moved) - JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(key), "' not found"), &j)); + JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", string_t(key), "' not found"), &j)); } return it->second; } @@ -30541,12 +30672,12 @@ public: // at only works for arrays if (JSON_HEDLEY_UNLIKELY(!j.is_array())) { - detail::throw_cannot_use_with(304, "at()", j); + detail::throw_cannot_use_with(detail::exception_id::at_wrong_type, "at()", j); } if (JSON_HEDLEY_UNLIKELY(idx >= j.m_data.m_value.array->size())) { - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &j)); + JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), &j)); } return (*j.m_data.m_value.array)[idx]; @@ -30579,6 +30710,15 @@ public: m_data.m_type = value_t::object; } + /// @brief throws because operator[] is not supported for the type of this value + /// @param[in] argument the kind of the operator's argument, "numeric" or "string" + /// @throw type_error.305 always + JSON_HEDLEY_NO_RETURN void throw_subscript_wrong_type(const char* argument) const + { + detail::throw_cannot_use_with(detail::exception_id::subscript_wrong_type, + detail::concat("operator[] with a ", argument, " argument").c_str(), *this); + } + public: //////////////////// // element access // @@ -30683,7 +30823,7 @@ public: return m_data.m_value.array->operator[](idx); } - detail::throw_cannot_use_with(305, "operator[] with a numeric argument", *this); + throw_subscript_wrong_type("numeric"); } /// @brief access specified array element @@ -30697,7 +30837,7 @@ public: return m_data.m_value.array->operator[](idx); } - detail::throw_cannot_use_with(305, "operator[] with a numeric argument", *this); + throw_subscript_wrong_type("numeric"); } /// @brief access specified object element @@ -30717,7 +30857,7 @@ public: return set_parent(result.first->second); } - detail::throw_cannot_use_with(305, "operator[] with a string argument", *this); + throw_subscript_wrong_type("string"); } /// @brief access specified object element @@ -30732,7 +30872,7 @@ public: return it->second; } - detail::throw_cannot_use_with(305, "operator[] with a string argument", *this); + throw_subscript_wrong_type("string"); } // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC @@ -30768,7 +30908,7 @@ public: return set_parent(result.first->second); } - detail::throw_cannot_use_with(305, "operator[] with a string argument", *this); + throw_subscript_wrong_type("string"); } /// @brief access specified object element @@ -30785,7 +30925,7 @@ public: return it->second; } - detail::throw_cannot_use_with(305, "operator[] with a string argument", *this); + throw_subscript_wrong_type("string"); } private: @@ -30809,7 +30949,7 @@ public: // value only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(306, "value()", *this); + detail::throw_cannot_use_with(detail::exception_id::value_wrong_type, "value()", *this); } const auto it = find(std::forward(key)); @@ -30824,7 +30964,7 @@ public: // value only works for arrays and objects if (JSON_HEDLEY_UNLIKELY(!is_structured())) { - detail::throw_cannot_use_with(306, "value()", *this); + detail::throw_cannot_use_with(detail::exception_id::value_wrong_type, "value()", *this); } return ptr.get_checked_or_null(this); @@ -30991,7 +31131,7 @@ public: // make sure the iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } IteratorType result = end(); @@ -31007,7 +31147,7 @@ public: { if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) { - JSON_THROW(invalid_iterator::create(205, "iterator out of range", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_out_of_range, "iterator out of range", this)); } m_data.m_value.destroy(m_data.m_type); @@ -31033,7 +31173,7 @@ public: case value_t::null: case value_t::discarded: default: - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } return result; @@ -31049,7 +31189,7 @@ public: // make sure the iterator fits the current value if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) { - JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_from_other_value, "iterators do not fit current value", this)); } IteratorType result = end(); @@ -31066,7 +31206,7 @@ public: if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() || !last.m_it.primitive_iterator.is_end())) { - JSON_THROW(invalid_iterator::create(204, "iterators out of range", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_out_of_range, "iterators out of range", this)); } m_data.m_value.destroy(m_data.m_type); @@ -31094,7 +31234,7 @@ public: case value_t::null: case value_t::discarded: default: - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } return result; @@ -31108,7 +31248,7 @@ public: // this erase only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } const auto erased = m_data.m_value.object->erase(std::forward(key)); @@ -31123,7 +31263,7 @@ public: // this erase only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } const auto it = object_lookup(*this, std::forward(key)); @@ -31165,14 +31305,14 @@ public: { if (JSON_HEDLEY_UNLIKELY(idx >= size())) { - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); + JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), this)); } m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast(idx)); } else { - detail::throw_cannot_use_with(307, "erase()", *this); + detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this); } } @@ -31661,7 +31801,7 @@ public: // push_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { - detail::throw_cannot_use_with(308, "push_back()", *this); + detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this); } // transform a null object into an array @@ -31692,7 +31832,7 @@ public: // push_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { - detail::throw_cannot_use_with(308, "push_back()", *this); + detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this); } // transform a null object into an array @@ -31722,7 +31862,7 @@ public: // push_back only works for null objects or objects if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) { - detail::throw_cannot_use_with(308, "push_back()", *this); + detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this); } // transform a null object into an object @@ -31776,7 +31916,7 @@ public: // emplace_back only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) { - detail::throw_cannot_use_with(311, "emplace_back()", *this); + detail::throw_cannot_use_with(detail::exception_id::emplace_wrong_type, "emplace_back()", *this); } // transform a null object into an array @@ -31799,7 +31939,7 @@ public: // emplace only works for null objects or arrays if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) { - detail::throw_cannot_use_with(311, "emplace()", *this); + detail::throw_cannot_use_with(detail::exception_id::emplace_wrong_type, "emplace()", *this); } // transform a null object into an object @@ -31851,14 +31991,14 @@ public: // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // insert to array and return iterator return insert_iterator(pos, val); } - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } /// @brief inserts element into array @@ -31871,7 +32011,7 @@ public: // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // moving into a local first keeps this safe even if val aliases @@ -31880,7 +32020,7 @@ public: return insert_iterator(pos, std::move(tmp)); } - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } /// @brief inserts copies of element into array @@ -31893,14 +32033,14 @@ public: // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // insert to array and return iterator return insert_iterator(pos, cnt, val); } - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } /// @brief inserts range of elements into array @@ -31910,30 +32050,30 @@ public: // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) { - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this)); } if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) { - JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_into_itself, "passed iterators may not belong to container", this)); } // passed iterators must belong to arrays if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_array())) { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to arrays", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterators first and last must point to arrays", this)); } // insert to array and return iterator @@ -31947,13 +32087,13 @@ public: // insert only works for arrays if (JSON_HEDLEY_UNLIKELY(!is_array())) { - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } // check if iterator pos fits to this JSON value if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this)); } // copy the values first: ilist may refer to elements of this array @@ -31975,19 +32115,19 @@ public: // insert only works for objects if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(309, "insert()", *this); + detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this); } // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this)); } // passed iterators must belong to objects if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterators first and last must point to objects", this)); } m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); @@ -32004,7 +32144,7 @@ public: // j, not the copy made below) if (JSON_HEDLEY_UNLIKELY(!j.is_object())) { - detail::throw_cannot_use_with(312, "update()", j); + detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", j); } // copy first: j may be *this or one of its descendants, and is @@ -32022,13 +32162,13 @@ public: // check if range iterators belong to the same JSON object if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this)); + JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this)); } // passed iterators must belong to objects if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) { - detail::throw_cannot_use_with(312, "update()", *first.m_object); + detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", *first.m_object); } // copy first: the range may belong to *this or one of its @@ -32064,7 +32204,7 @@ public: if (JSON_HEDLEY_UNLIKELY(!is_object())) { - detail::throw_cannot_use_with(312, "update()", *this); + detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", *this); } } @@ -32227,7 +32367,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(array_t&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(array_t&)", *this); } } @@ -32244,7 +32384,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(object_t&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(object_t&)", *this); } } @@ -32260,7 +32400,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(string_t&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(string_t&)", *this); } } @@ -32276,7 +32416,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(binary_t&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(binary_t&)", *this); } } @@ -32292,7 +32432,7 @@ public: } else { - detail::throw_cannot_use_with(310, "swap(binary_t::container_type&)", *this); + detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(binary_t::container_type&)", *this); } } @@ -33754,7 +33894,7 @@ public: if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) { // avoid undefined behavior - JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent)); + JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent)); } // default case: insert add offset @@ -33773,7 +33913,7 @@ public: case value_t::binary: case value_t::discarded: default: - JSON_THROW(out_of_range::create(411, detail::concat("cannot add value: the JSON Patch 'add' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent)); + JSON_THROW(out_of_range::create(detail::exception_id::patch_add_parent_not_container, detail::concat("cannot add value: the JSON Patch 'add' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent)); } }; @@ -33796,7 +33936,7 @@ public: } else { - JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this)); + JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", last_path, "' not found"), this)); } } else if (parent.is_array()) @@ -33808,7 +33948,7 @@ public: { // the parent of a "remove" target must be an object or array // (see #5396) - JSON_THROW(out_of_range::create(413, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent)); + JSON_THROW(out_of_range::create(detail::exception_id::patch_remove_parent_not_container, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent)); } }; @@ -33839,7 +33979,7 @@ public: // type check: top level value must be an array if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch)); + JSON_THROW(parse_error::create(detail::exception_id::patch_not_an_array, 0, "JSON patch must be an array of objects", &json_patch)); } // iterate and apply the operations @@ -33860,14 +34000,14 @@ public: if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val)); + JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat(error_msg, " must have member '", member, "'"), &val)); } // check if the result is of type string if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) { // NOLINTNEXTLINE(performance-inefficient-string-concatenation) - JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val)); + JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val)); } // no error: return value @@ -33877,7 +34017,7 @@ public: // type check: every element of the array must be an object if (JSON_HEDLEY_UNLIKELY(!val.is_object())) { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val)); + JSON_THROW(parse_error::create(detail::exception_id::patch_not_an_array, 0, "JSON patch must be an array of objects", &val)); } // collect mandatory members @@ -33913,7 +34053,7 @@ public: if (JSON_HEDLEY_UNLIKELY(is_proper_prefix(from_ptr, ptr))) { - JSON_THROW(out_of_range::create(414, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result)); + JSON_THROW(out_of_range::create(detail::exception_id::patch_move_into_child, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result)); } // the "from" location must exist - use at() @@ -33960,7 +34100,7 @@ public: // throw an exception if the test fails if (JSON_HEDLEY_UNLIKELY(!success)) { - JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val)); + JSON_THROW(other_error::create(detail::exception_id::patch_test_failed, detail::concat("unsuccessful: ", val.dump()), &val)); } break; @@ -33971,7 +34111,7 @@ public: { // op must be "add", "remove", "replace", "move", "copy", or // "test" - JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val)); + JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat("operation value '", op, "' is invalid"), &val)); } } } diff --git a/tests/src/fuzzer-parse_bjdata.cpp b/tests/src/fuzzer-parse_bjdata.cpp index a56e2af37..92e1bed4c 100644 --- a/tests/src/fuzzer-parse_bjdata.cpp +++ b/tests/src/fuzzer-parse_bjdata.cpp @@ -51,12 +51,8 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer drivers. */ -#include -#include #include "fuzzer_common.hpp" -using nlohmann::json; - // value-stable comparison for the round-trip checks below; see the note // above on why this compares dump()s rather than the json values directly static bool is_value_stable(const json& lhs, const json& rhs) diff --git a/tests/src/fuzzer-parse_bon8.cpp b/tests/src/fuzzer-parse_bon8.cpp index 98c1a0f25..792606d05 100644 --- a/tests/src/fuzzer-parse_bon8.cpp +++ b/tests/src/fuzzer-parse_bon8.cpp @@ -25,13 +25,9 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer drivers. */ -#include #include -#include #include "fuzzer_common.hpp" -using nlohmann::json; - namespace { // the serialization of the value read from @a input, or the error message diff --git a/tests/src/fuzzer-parse_bson.cpp b/tests/src/fuzzer-parse_bson.cpp index b7abc6413..548c30f38 100644 --- a/tests/src/fuzzer-parse_bson.cpp +++ b/tests/src/fuzzer-parse_bson.cpp @@ -21,12 +21,8 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer drivers. */ -#include -#include #include "fuzzer_common.hpp" -using nlohmann::json; - // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/tests/src/fuzzer-parse_cbor.cpp b/tests/src/fuzzer-parse_cbor.cpp index 3232996ce..6d995dc6e 100644 --- a/tests/src/fuzzer-parse_cbor.cpp +++ b/tests/src/fuzzer-parse_cbor.cpp @@ -21,12 +21,8 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer drivers. */ -#include -#include #include "fuzzer_common.hpp" -using nlohmann::json; - // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/tests/src/fuzzer-parse_json.cpp b/tests/src/fuzzer-parse_json.cpp index c1259d152..31a811a6c 100644 --- a/tests/src/fuzzer-parse_json.cpp +++ b/tests/src/fuzzer-parse_json.cpp @@ -22,12 +22,8 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer drivers. */ -#include -#include #include "fuzzer_common.hpp" -using nlohmann::json; - // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/tests/src/fuzzer-parse_msgpack.cpp b/tests/src/fuzzer-parse_msgpack.cpp index cb92c9b39..a5e2e346f 100644 --- a/tests/src/fuzzer-parse_msgpack.cpp +++ b/tests/src/fuzzer-parse_msgpack.cpp @@ -21,12 +21,8 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer drivers. */ -#include -#include #include "fuzzer_common.hpp" -using nlohmann::json; - // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/tests/src/fuzzer-parse_ubjson.cpp b/tests/src/fuzzer-parse_ubjson.cpp index d8cbced93..641526c90 100644 --- a/tests/src/fuzzer-parse_ubjson.cpp +++ b/tests/src/fuzzer-parse_ubjson.cpp @@ -30,12 +30,8 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer drivers. */ -#include -#include #include "fuzzer_common.hpp" -using nlohmann::json; - // see http://llvm.org/docs/LibFuzzer.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { diff --git a/tests/src/fuzzer_common.hpp b/tests/src/fuzzer_common.hpp index ed6e4d9cd..4b6c9289c 100644 --- a/tests/src/fuzzer_common.hpp +++ b/tests/src/fuzzer_common.hpp @@ -13,6 +13,8 @@ #include // assert #include +using nlohmann::json; // NOLINT(google-global-names-in-headers): shared by all fuzzer drivers + // the round-trip checks of the drivers are assertions; NDEBUG would compile them away #ifdef NDEBUG #error "the fuzzer drivers must be built without NDEBUG" @@ -20,9 +22,9 @@ // compares dumps rather than values, because NaN != NaN; keep writes strings // byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw -inline bool same_value(const nlohmann::json& lhs, const nlohmann::json& rhs) +inline bool same_value(const json& lhs, const json& rhs) { - return lhs.dump(-1, ' ', false, nlohmann::json::error_handler_t::keep) == rhs.dump(-1, ' ', false, nlohmann::json::error_handler_t::keep); + return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep); } // step 0 of each driver: parse the input without exceptions; a parse error @@ -30,18 +32,18 @@ inline bool same_value(const nlohmann::json& lhs, const nlohmann::json& rhs) // out-of-range errors are not parse errors and still throw; then @a threw is // set and null is returned. template -nlohmann::json parse_without_exceptions(Parse parse, bool& threw) +json parse_without_exceptions(Parse parse, bool& threw) { threw = false; try { return parse(); } - catch (const nlohmann::json::parse_error&) + catch (const json::parse_error&) { assert(false); } - catch (const nlohmann::json::exception&) + catch (const json::exception&) { threw = true; } diff --git a/tests/src/test_sax.hpp b/tests/src/sax_event_loggers.hpp similarity index 100% rename from tests/src/test_sax.hpp rename to tests/src/sax_event_loggers.hpp diff --git a/tests/src/unit-class_parser.cpp b/tests/src/unit-class_parser.cpp index 2f6f5989a..3245d76b9 100644 --- a/tests/src/unit-class_parser.cpp +++ b/tests/src/unit-class_parser.cpp @@ -38,7 +38,7 @@ using nlohmann::json; #include #include "sax_countdown.hpp" -#include "test_sax.hpp" +#include "sax_event_loggers.hpp" #include "test_utils.hpp" using utils::SaxCountdown; diff --git a/tests/src/unit-deserialization.cpp b/tests/src/unit-deserialization.cpp index 300e7708a..6222def34 100644 --- a/tests/src/unit-deserialization.cpp +++ b/tests/src/unit-deserialization.cpp @@ -36,7 +36,7 @@ using nlohmann::json; #include #include -#include "test_sax.hpp" +#include "sax_event_loggers.hpp" using utils::SaxEventLogger; using utils::SaxEventLoggerExitAfterKey;