From 1ab26ab36750fd7426014b55bf6efdd7e0339216 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 16 Jan 2017 22:11:07 +0100 Subject: [PATCH 1/3] :sparkles: option to switch off exceptions --- .travis.yml | 15 ++ src/json.hpp | 262 ++++++++++++++++-------------- src/json.hpp.re2c | 262 ++++++++++++++++-------------- test/Makefile | 2 +- test/src/unit-cbor.cpp | 2 +- test/src/unit-element_access2.cpp | 53 +++--- 6 files changed, 335 insertions(+), 261 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6bf2297e2..6a154deb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,6 +71,21 @@ matrix: after_success: - make cppcheck + # no exceptions + + - os: linux + compiler: gcc + env: + - COMPILER=g++-4.9 + - SPECIAL=no_exceptions + - TEST_PATTERN="-e \"*\"" + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: [g++-4.9, cppcheck] + before_script: + - make FLAGS="-fno-exceptions" + # Coveralls (http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/) - os: linux diff --git a/src/json.hpp b/src/json.hpp index 3200e095a..69d49ec17 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -88,6 +88,17 @@ SOFTWARE. #define JSON_DEPRECATED #endif +// allow to disable exceptions +#if defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) +#else + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) +#endif + /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @@ -945,7 +956,7 @@ class basic_json { if (t == value_t::null) { - throw std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10"); // LCOV_EXCL_LINE + JSON_THROW(std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10")); // LCOV_EXCL_LINE } break; } @@ -1717,7 +1728,7 @@ class basic_json // if object is wanted but impossible, throw an exception if (manual_type == value_t::object and not is_an_object) { - throw std::domain_error("cannot create object from initializer list"); + JSON_THROW(std::domain_error("cannot create object from initializer list")); } } @@ -1895,7 +1906,7 @@ class basic_json // make sure iterator fits the current value if (first.m_object != last.m_object) { - throw std::domain_error("iterators are not compatible"); + JSON_THROW(std::domain_error("iterators are not compatible")); } // copy type from first iterator @@ -1912,7 +1923,7 @@ class basic_json { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { - throw std::out_of_range("iterators out of range"); + JSON_THROW(std::out_of_range("iterators out of range")); } break; } @@ -1971,7 +1982,7 @@ class basic_json default: { - throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); + JSON_THROW(std::domain_error("cannot use construct with iterators from " + first.m_object->type_name())); } } @@ -2655,7 +2666,7 @@ class basic_json return T(m_value.object->begin(), m_value.object->end()); } - throw std::domain_error("type must be object, but is " + type_name()); + JSON_THROW(std::domain_error("type must be object, but is " + type_name())); } /// get an object (explicit) @@ -2666,7 +2677,7 @@ class basic_json return *(m_value.object); } - throw std::domain_error("type must be object, but is " + type_name()); + JSON_THROW(std::domain_error("type must be object, but is " + type_name())); } /// get an array (explicit) @@ -2689,7 +2700,7 @@ class basic_json return to_vector; } - throw std::domain_error("type must be array, but is " + type_name()); + JSON_THROW(std::domain_error("type must be array, but is " + type_name())); } /// get an array (explicit) @@ -2710,7 +2721,7 @@ class basic_json return to_vector; } - throw std::domain_error("type must be array, but is " + type_name()); + JSON_THROW(std::domain_error("type must be array, but is " + type_name())); } /// get an array (explicit) @@ -2724,7 +2735,7 @@ class basic_json return T(m_value.array->begin(), m_value.array->end()); } - throw std::domain_error("type must be array, but is " + type_name()); + JSON_THROW(std::domain_error("type must be array, but is " + type_name())); } /// get an array (explicit) @@ -2735,7 +2746,7 @@ class basic_json return *(m_value.array); } - throw std::domain_error("type must be array, but is " + type_name()); + JSON_THROW(std::domain_error("type must be array, but is " + type_name())); } /// get a string (explicit) @@ -2748,7 +2759,7 @@ class basic_json return *m_value.string; } - throw std::domain_error("type must be string, but is " + type_name()); + JSON_THROW(std::domain_error("type must be string, but is " + type_name())); } /// get a number (explicit) @@ -2775,17 +2786,22 @@ class basic_json default: { - throw std::domain_error("type must be number, but is " + type_name()); + JSON_THROW(std::domain_error("type must be number, but is " + type_name())); } } } /// get a boolean (explicit) - constexpr boolean_t get_impl(boolean_t* /*unused*/) const + boolean_t get_impl(boolean_t* /*unused*/) const { - return is_boolean() - ? m_value.boolean - : throw std::domain_error("type must be boolean, but is " + type_name()); + if (is_boolean()) + { + return m_value.boolean; + } + else + { + JSON_THROW(std::domain_error("type must be boolean, but is " + type_name())); + } } /// get a pointer to the value (object) @@ -3197,19 +3213,19 @@ class basic_json // at only works for arrays if (is_array()) { - try + JSON_TRY { return m_value.array->at(idx); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // create better exception explanation - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); } } else { - throw std::domain_error("cannot use at() with " + type_name()); + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); } } @@ -3240,19 +3256,19 @@ class basic_json // at only works for arrays if (is_array()) { - try + JSON_TRY { return m_value.array->at(idx); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // create better exception explanation - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); } } else { - throw std::domain_error("cannot use at() with " + type_name()); + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); } } @@ -3287,19 +3303,19 @@ class basic_json // at only works for objects if (is_object()) { - try + JSON_TRY { return m_value.object->at(key); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // create better exception explanation - throw std::out_of_range("key '" + key + "' not found"); + JSON_THROW(std::out_of_range("key '" + key + "' not found")); } } else { - throw std::domain_error("cannot use at() with " + type_name()); + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); } } @@ -3334,19 +3350,19 @@ class basic_json // at only works for objects if (is_object()) { - try + JSON_TRY { return m_value.object->at(key); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // create better exception explanation - throw std::out_of_range("key '" + key + "' not found"); + JSON_THROW(std::out_of_range("key '" + key + "' not found")); } } else { - throw std::domain_error("cannot use at() with " + type_name()); + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); } } @@ -3399,7 +3415,7 @@ class basic_json return m_value.array->operator[](idx); } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3429,7 +3445,7 @@ class basic_json return m_value.array->operator[](idx); } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3475,7 +3491,7 @@ class basic_json return m_value.object->operator[](key); } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3517,7 +3533,7 @@ class basic_json return m_value.object->find(key)->second; } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3632,7 +3648,7 @@ class basic_json return m_value.object->operator[](key); } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3675,7 +3691,7 @@ class basic_json return m_value.object->find(key)->second; } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3744,7 +3760,7 @@ class basic_json } else { - throw std::domain_error("cannot use value() with " + type_name()); + JSON_THROW(std::domain_error("cannot use value() with " + type_name())); } } @@ -3806,17 +3822,17 @@ class basic_json if (is_object()) { // if pointer resolves a value, return it or use default value - try + JSON_TRY { return ptr.get_checked(this); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { return default_value; } } - throw std::domain_error("cannot use value() with " + type_name()); + JSON_THROW(std::domain_error("cannot use value() with " + type_name())); } /*! @@ -3967,7 +3983,7 @@ class basic_json // make sure iterator fits the current value if (this != pos.m_object) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } IteratorType result = end(); @@ -3982,7 +3998,7 @@ class basic_json { if (not pos.m_it.primitive_iterator.is_begin()) { - throw std::out_of_range("iterator out of range"); + JSON_THROW(std::out_of_range("iterator out of range")); } if (is_string()) @@ -4012,7 +4028,7 @@ class basic_json default: { - throw std::domain_error("cannot use erase() with " + type_name()); + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); } } @@ -4074,7 +4090,7 @@ class basic_json // make sure iterator fits the current value if (this != first.m_object or this != last.m_object) { - throw std::domain_error("iterators do not fit current value"); + JSON_THROW(std::domain_error("iterators do not fit current value")); } IteratorType result = end(); @@ -4089,7 +4105,7 @@ class basic_json { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { - throw std::out_of_range("iterators out of range"); + JSON_THROW(std::out_of_range("iterators out of range")); } if (is_string()) @@ -4121,7 +4137,7 @@ class basic_json default: { - throw std::domain_error("cannot use erase() with " + type_name()); + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); } } @@ -4165,7 +4181,7 @@ class basic_json return m_value.object->erase(key); } - throw std::domain_error("cannot use erase() with " + type_name()); + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); } /*! @@ -4199,14 +4215,14 @@ class basic_json { if (idx >= size()) { - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); } m_value.array->erase(m_value.array->begin() + static_cast(idx)); } else { - throw std::domain_error("cannot use erase() with " + type_name()); + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); } } @@ -4924,7 +4940,7 @@ class basic_json // push_back only works for null objects or arrays if (not(is_null() or is_array())) { - throw std::domain_error("cannot use push_back() with " + type_name()); + JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); } // transform null object into an array @@ -4960,7 +4976,7 @@ class basic_json // push_back only works for null objects or arrays if (not(is_null() or is_array())) { - throw std::domain_error("cannot use push_back() with " + type_name()); + JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); } // transform null object into an array @@ -5010,7 +5026,7 @@ class basic_json // push_back only works for null objects or objects if (not(is_null() or is_object())) { - throw std::domain_error("cannot use push_back() with " + type_name()); + JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); } // transform null object into an object @@ -5110,7 +5126,7 @@ class basic_json // emplace_back only works for null objects or arrays if (not(is_null() or is_array())) { - throw std::domain_error("cannot use emplace_back() with " + type_name()); + JSON_THROW(std::domain_error("cannot use emplace_back() with " + type_name())); } // transform null object into an array @@ -5158,7 +5174,7 @@ class basic_json // emplace only works for null objects or arrays if (not(is_null() or is_object())) { - throw std::domain_error("cannot use emplace() with " + type_name()); + JSON_THROW(std::domain_error("cannot use emplace() with " + type_name())); } // transform null object into an object @@ -5209,7 +5225,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } // insert to array and return iterator @@ -5218,7 +5234,7 @@ class basic_json return result; } - throw std::domain_error("cannot use insert() with " + type_name()); + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); } /*! @@ -5262,7 +5278,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } // insert to array and return iterator @@ -5271,7 +5287,7 @@ class basic_json return result; } - throw std::domain_error("cannot use insert() with " + type_name()); + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); } /*! @@ -5309,24 +5325,24 @@ class basic_json // insert only works for arrays if (not is_array()) { - throw std::domain_error("cannot use insert() with " + type_name()); + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); } // check if iterator pos fits to this JSON value if (pos.m_object != this) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } // check if range iterators belong to the same JSON object if (first.m_object != last.m_object) { - throw std::domain_error("iterators do not fit"); + JSON_THROW(std::domain_error("iterators do not fit")); } if (first.m_object == this or last.m_object == this) { - throw std::domain_error("passed iterators may not belong to container"); + JSON_THROW(std::domain_error("passed iterators may not belong to container")); } // insert to array and return iterator @@ -5367,13 +5383,13 @@ class basic_json // insert only works for arrays if (not is_array()) { - throw std::domain_error("cannot use insert() with " + type_name()); + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); } // check if iterator pos fits to this JSON value if (pos.m_object != this) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } // insert to array and return iterator @@ -5440,7 +5456,7 @@ class basic_json } else { - throw std::domain_error("cannot use swap() with " + type_name()); + JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); } } @@ -5473,7 +5489,7 @@ class basic_json } else { - throw std::domain_error("cannot use swap() with " + type_name()); + JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); } } @@ -5506,7 +5522,7 @@ class basic_json } else { - throw std::domain_error("cannot use swap() with " + type_name()); + JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); } } @@ -6350,7 +6366,7 @@ class basic_json { if (current_index + sizeof(T) + 1 > vec.size()) { - throw std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector"); + JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); } T result; @@ -6900,19 +6916,19 @@ class basic_json // simple case: requested length is greater than the vector's length if (len > size or offset > size) { - throw std::out_of_range("len out of range"); + JSON_THROW(std::out_of_range("len out of range")); } // second case: adding offset would result in overflow if ((size > (std::numeric_limits::max() - offset))) { - throw std::out_of_range("len+offset out of range"); + JSON_THROW(std::out_of_range("len+offset out of range")); } // last case: reading past the end of the vector if (len + offset > size) { - throw std::out_of_range("len+offset out of range"); + JSON_THROW(std::out_of_range("len+offset out of range")); } } @@ -7148,7 +7164,7 @@ class basic_json default: { - throw std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx]))); + JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); } } } @@ -7631,7 +7647,7 @@ class basic_json default: // anything else (0xFF is handled inside the other types) { - throw std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx]))); + JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); } } } @@ -8521,7 +8537,7 @@ class basic_json case basic_json::value_t::null: { - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } default: @@ -8531,7 +8547,7 @@ class basic_json return *m_object; } - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } } } @@ -8565,7 +8581,7 @@ class basic_json return m_object; } - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } } } @@ -8665,7 +8681,7 @@ class basic_json // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { - throw std::domain_error("cannot compare iterators of different containers"); + JSON_THROW(std::domain_error("cannot compare iterators of different containers")); } assert(m_object != nullptr); @@ -8707,7 +8723,7 @@ class basic_json // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { - throw std::domain_error("cannot compare iterators of different containers"); + JSON_THROW(std::domain_error("cannot compare iterators of different containers")); } assert(m_object != nullptr); @@ -8716,7 +8732,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot compare order of object iterators"); + JSON_THROW(std::domain_error("cannot compare order of object iterators")); } case basic_json::value_t::array: @@ -8770,7 +8786,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use offsets with object iterators"); + JSON_THROW(std::domain_error("cannot use offsets with object iterators")); } case basic_json::value_t::array: @@ -8832,7 +8848,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use offsets with object iterators"); + JSON_THROW(std::domain_error("cannot use offsets with object iterators")); } case basic_json::value_t::array: @@ -8859,7 +8875,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use operator[] for object iterators"); + JSON_THROW(std::domain_error("cannot use operator[] for object iterators")); } case basic_json::value_t::array: @@ -8869,7 +8885,7 @@ class basic_json case basic_json::value_t::null: { - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } default: @@ -8879,7 +8895,7 @@ class basic_json return *m_object; } - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } } } @@ -8897,7 +8913,7 @@ class basic_json return m_it.object_iterator->first; } - throw std::domain_error("cannot use key() for non-object iterators"); + JSON_THROW(std::domain_error("cannot use key() for non-object iterators")); } /*! @@ -9082,7 +9098,7 @@ class basic_json // immediately abort if stream is erroneous if (s.fail()) { - throw std::invalid_argument("stream error"); + JSON_THROW(std::invalid_argument("stream error")); } // fill buffer @@ -9149,7 +9165,7 @@ class basic_json } else { - throw std::invalid_argument("missing or wrong low surrogate"); + JSON_THROW(std::invalid_argument("missing or wrong low surrogate")); } } @@ -9183,7 +9199,7 @@ class basic_json } else { - throw std::out_of_range("code points above 0x10FFFF are invalid"); + JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid")); } return result; @@ -10415,7 +10431,7 @@ basic_json_parser_66: // make sure there is a subsequent unicode if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') { - throw std::invalid_argument("missing low surrogate"); + JSON_THROW(std::invalid_argument("missing low surrogate")); } // get code yyyy from uxxxx\uyyyy @@ -10428,7 +10444,7 @@ basic_json_parser_66: else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF) { // we found a lone low surrogate - throw std::invalid_argument("missing high surrogate"); + JSON_THROW(std::invalid_argument("missing high surrogate")); } else { @@ -10906,7 +10922,7 @@ basic_json_parser_66: "'") : lexer::token_type_name(last_token)); error_msg += "; expected " + lexer::token_type_name(t); - throw std::invalid_argument(error_msg); + JSON_THROW(std::invalid_argument(error_msg)); } } @@ -10918,7 +10934,7 @@ basic_json_parser_66: error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + "'") : lexer::token_type_name(last_token)); - throw std::invalid_argument(error_msg); + JSON_THROW(std::invalid_argument(error_msg)); } } @@ -11014,7 +11030,7 @@ basic_json_parser_66: { if (is_root()) { - throw std::domain_error("JSON pointer has no parent"); + JSON_THROW(std::domain_error("JSON pointer has no parent")); } auto last = reference_tokens.back(); @@ -11032,7 +11048,7 @@ basic_json_parser_66: { if (is_root()) { - throw std::domain_error("JSON pointer has no parent"); + JSON_THROW(std::domain_error("JSON pointer has no parent")); } json_pointer result = *this; @@ -11093,7 +11109,7 @@ basic_json_parser_66: */ default: { - throw std::domain_error("invalid value to unflatten"); + JSON_THROW(std::domain_error("invalid value to unflatten")); } } } @@ -11161,7 +11177,7 @@ basic_json_parser_66: // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - throw std::domain_error("array index must not begin with '0'"); + JSON_THROW(std::domain_error("array index must not begin with '0'")); } if (reference_token == "-") @@ -11179,7 +11195,7 @@ basic_json_parser_66: default: { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); } } } @@ -11213,7 +11229,7 @@ basic_json_parser_66: // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - throw std::domain_error("array index must not begin with '0'"); + JSON_THROW(std::domain_error("array index must not begin with '0'")); } // note: at performs range check @@ -11223,7 +11239,7 @@ basic_json_parser_66: default: { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); } } } @@ -11265,7 +11281,7 @@ basic_json_parser_66: // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - throw std::domain_error("array index must not begin with '0'"); + JSON_THROW(std::domain_error("array index must not begin with '0'")); } // use unchecked array access @@ -11275,7 +11291,7 @@ basic_json_parser_66: default: { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); } } } @@ -11309,7 +11325,7 @@ basic_json_parser_66: // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - throw std::domain_error("array index must not begin with '0'"); + JSON_THROW(std::domain_error("array index must not begin with '0'")); } // note: at performs range check @@ -11319,7 +11335,7 @@ basic_json_parser_66: default: { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); } } } @@ -11341,7 +11357,7 @@ basic_json_parser_66: // check if nonempty reference string begins with slash if (reference_string[0] != '/') { - throw std::domain_error("JSON pointer must be empty or begin with '/'"); + JSON_THROW(std::domain_error("JSON pointer must be empty or begin with '/'")); } // extract the reference tokens: @@ -11376,7 +11392,7 @@ basic_json_parser_66: (reference_token[pos + 1] != '0' and reference_token[pos + 1] != '1')) { - throw std::domain_error("escape error: '~' must be followed with '0' or '1'"); + JSON_THROW(std::domain_error("escape error: '~' must be followed with '0' or '1'")); } } @@ -11502,7 +11518,7 @@ basic_json_parser_66: { if (not value.is_object()) { - throw std::domain_error("only objects can be unflattened"); + JSON_THROW(std::domain_error("only objects can be unflattened")); } basic_json result; @@ -11512,7 +11528,7 @@ basic_json_parser_66: { if (not element.second.is_primitive()) { - throw std::domain_error("values in object must be primitive"); + JSON_THROW(std::domain_error("values in object must be primitive")); } // assign value to reference pointed to by JSON pointer; Note @@ -11841,7 +11857,7 @@ basic_json_parser_66: if (static_cast(idx) > parent.size()) { // avoid undefined behavior - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); } else { @@ -11879,7 +11895,7 @@ basic_json_parser_66: } else { - throw std::out_of_range("key '" + last_path + "' not found"); + JSON_THROW(std::out_of_range("key '" + last_path + "' not found")); } } else if (parent.is_array()) @@ -11893,7 +11909,7 @@ basic_json_parser_66: if (not json_patch.is_array()) { // a JSON patch must be an array of objects - throw std::invalid_argument("JSON patch must be an array of objects"); + JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); } // iterate and apply th eoperations @@ -11913,13 +11929,13 @@ basic_json_parser_66: // check if desired value is present if (it == val.m_value.object->end()) { - throw std::invalid_argument(error_msg + " must have member '" + member + "'"); + JSON_THROW(std::invalid_argument(error_msg + " must have member '" + member + "'")); } // check if result is of type string if (string_type and not it->second.is_string()) { - throw std::invalid_argument(error_msg + " must have string member '" + member + "'"); + JSON_THROW(std::invalid_argument(error_msg + " must have string member '" + member + "'")); } // no error: return value @@ -11929,7 +11945,7 @@ basic_json_parser_66: // type check if (not val.is_object()) { - throw std::invalid_argument("JSON patch must be an array of objects"); + JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); } // collect mandatory members @@ -11988,13 +12004,13 @@ basic_json_parser_66: case patch_operations::test: { bool success = false; - try + JSON_TRY { // check if "value" matches the one at "path" // the "path" location must exist - use at() success = (result.at(ptr) == get_value("test", "value", false)); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // ignore out of range errors: success remains false } @@ -12002,7 +12018,7 @@ basic_json_parser_66: // throw an exception if test fails if (not success) { - throw std::domain_error("unsuccessful: " + val.dump()); + JSON_THROW(std::domain_error("unsuccessful: " + val.dump())); } break; @@ -12012,7 +12028,7 @@ basic_json_parser_66: { // op must be "add", "remove", "replace", "move", "copy", or // "test" - throw std::invalid_argument("operation value '" + op + "' is invalid"); + JSON_THROW(std::invalid_argument("operation value '" + op + "' is invalid")); } } } @@ -12285,4 +12301,10 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #pragma GCC diagnostic pop #endif +// clean up +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_CATCH +#undef JSON_DEPRECATED + #endif diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index c7171a276..31accc98f 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -88,6 +88,17 @@ SOFTWARE. #define JSON_DEPRECATED #endif +// allow to disable exceptions +#if defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) +#else + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) +#endif + /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @@ -945,7 +956,7 @@ class basic_json { if (t == value_t::null) { - throw std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10"); // LCOV_EXCL_LINE + JSON_THROW(std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10")); // LCOV_EXCL_LINE } break; } @@ -1717,7 +1728,7 @@ class basic_json // if object is wanted but impossible, throw an exception if (manual_type == value_t::object and not is_an_object) { - throw std::domain_error("cannot create object from initializer list"); + JSON_THROW(std::domain_error("cannot create object from initializer list")); } } @@ -1895,7 +1906,7 @@ class basic_json // make sure iterator fits the current value if (first.m_object != last.m_object) { - throw std::domain_error("iterators are not compatible"); + JSON_THROW(std::domain_error("iterators are not compatible")); } // copy type from first iterator @@ -1912,7 +1923,7 @@ class basic_json { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { - throw std::out_of_range("iterators out of range"); + JSON_THROW(std::out_of_range("iterators out of range")); } break; } @@ -1971,7 +1982,7 @@ class basic_json default: { - throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); + JSON_THROW(std::domain_error("cannot use construct with iterators from " + first.m_object->type_name())); } } @@ -2655,7 +2666,7 @@ class basic_json return T(m_value.object->begin(), m_value.object->end()); } - throw std::domain_error("type must be object, but is " + type_name()); + JSON_THROW(std::domain_error("type must be object, but is " + type_name())); } /// get an object (explicit) @@ -2666,7 +2677,7 @@ class basic_json return *(m_value.object); } - throw std::domain_error("type must be object, but is " + type_name()); + JSON_THROW(std::domain_error("type must be object, but is " + type_name())); } /// get an array (explicit) @@ -2689,7 +2700,7 @@ class basic_json return to_vector; } - throw std::domain_error("type must be array, but is " + type_name()); + JSON_THROW(std::domain_error("type must be array, but is " + type_name())); } /// get an array (explicit) @@ -2710,7 +2721,7 @@ class basic_json return to_vector; } - throw std::domain_error("type must be array, but is " + type_name()); + JSON_THROW(std::domain_error("type must be array, but is " + type_name())); } /// get an array (explicit) @@ -2724,7 +2735,7 @@ class basic_json return T(m_value.array->begin(), m_value.array->end()); } - throw std::domain_error("type must be array, but is " + type_name()); + JSON_THROW(std::domain_error("type must be array, but is " + type_name())); } /// get an array (explicit) @@ -2735,7 +2746,7 @@ class basic_json return *(m_value.array); } - throw std::domain_error("type must be array, but is " + type_name()); + JSON_THROW(std::domain_error("type must be array, but is " + type_name())); } /// get a string (explicit) @@ -2748,7 +2759,7 @@ class basic_json return *m_value.string; } - throw std::domain_error("type must be string, but is " + type_name()); + JSON_THROW(std::domain_error("type must be string, but is " + type_name())); } /// get a number (explicit) @@ -2775,17 +2786,22 @@ class basic_json default: { - throw std::domain_error("type must be number, but is " + type_name()); + JSON_THROW(std::domain_error("type must be number, but is " + type_name())); } } } /// get a boolean (explicit) - constexpr boolean_t get_impl(boolean_t* /*unused*/) const + boolean_t get_impl(boolean_t* /*unused*/) const { - return is_boolean() - ? m_value.boolean - : throw std::domain_error("type must be boolean, but is " + type_name()); + if (is_boolean()) + { + return m_value.boolean; + } + else + { + JSON_THROW(std::domain_error("type must be boolean, but is " + type_name())); + } } /// get a pointer to the value (object) @@ -3197,19 +3213,19 @@ class basic_json // at only works for arrays if (is_array()) { - try + JSON_TRY { return m_value.array->at(idx); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // create better exception explanation - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); } } else { - throw std::domain_error("cannot use at() with " + type_name()); + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); } } @@ -3240,19 +3256,19 @@ class basic_json // at only works for arrays if (is_array()) { - try + JSON_TRY { return m_value.array->at(idx); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // create better exception explanation - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); } } else { - throw std::domain_error("cannot use at() with " + type_name()); + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); } } @@ -3287,19 +3303,19 @@ class basic_json // at only works for objects if (is_object()) { - try + JSON_TRY { return m_value.object->at(key); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // create better exception explanation - throw std::out_of_range("key '" + key + "' not found"); + JSON_THROW(std::out_of_range("key '" + key + "' not found")); } } else { - throw std::domain_error("cannot use at() with " + type_name()); + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); } } @@ -3334,19 +3350,19 @@ class basic_json // at only works for objects if (is_object()) { - try + JSON_TRY { return m_value.object->at(key); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // create better exception explanation - throw std::out_of_range("key '" + key + "' not found"); + JSON_THROW(std::out_of_range("key '" + key + "' not found")); } } else { - throw std::domain_error("cannot use at() with " + type_name()); + JSON_THROW(std::domain_error("cannot use at() with " + type_name())); } } @@ -3399,7 +3415,7 @@ class basic_json return m_value.array->operator[](idx); } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3429,7 +3445,7 @@ class basic_json return m_value.array->operator[](idx); } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3475,7 +3491,7 @@ class basic_json return m_value.object->operator[](key); } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3517,7 +3533,7 @@ class basic_json return m_value.object->find(key)->second; } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3632,7 +3648,7 @@ class basic_json return m_value.object->operator[](key); } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3675,7 +3691,7 @@ class basic_json return m_value.object->find(key)->second; } - throw std::domain_error("cannot use operator[] with " + type_name()); + JSON_THROW(std::domain_error("cannot use operator[] with " + type_name())); } /*! @@ -3744,7 +3760,7 @@ class basic_json } else { - throw std::domain_error("cannot use value() with " + type_name()); + JSON_THROW(std::domain_error("cannot use value() with " + type_name())); } } @@ -3806,17 +3822,17 @@ class basic_json if (is_object()) { // if pointer resolves a value, return it or use default value - try + JSON_TRY { return ptr.get_checked(this); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { return default_value; } } - throw std::domain_error("cannot use value() with " + type_name()); + JSON_THROW(std::domain_error("cannot use value() with " + type_name())); } /*! @@ -3967,7 +3983,7 @@ class basic_json // make sure iterator fits the current value if (this != pos.m_object) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } IteratorType result = end(); @@ -3982,7 +3998,7 @@ class basic_json { if (not pos.m_it.primitive_iterator.is_begin()) { - throw std::out_of_range("iterator out of range"); + JSON_THROW(std::out_of_range("iterator out of range")); } if (is_string()) @@ -4012,7 +4028,7 @@ class basic_json default: { - throw std::domain_error("cannot use erase() with " + type_name()); + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); } } @@ -4074,7 +4090,7 @@ class basic_json // make sure iterator fits the current value if (this != first.m_object or this != last.m_object) { - throw std::domain_error("iterators do not fit current value"); + JSON_THROW(std::domain_error("iterators do not fit current value")); } IteratorType result = end(); @@ -4089,7 +4105,7 @@ class basic_json { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) { - throw std::out_of_range("iterators out of range"); + JSON_THROW(std::out_of_range("iterators out of range")); } if (is_string()) @@ -4121,7 +4137,7 @@ class basic_json default: { - throw std::domain_error("cannot use erase() with " + type_name()); + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); } } @@ -4165,7 +4181,7 @@ class basic_json return m_value.object->erase(key); } - throw std::domain_error("cannot use erase() with " + type_name()); + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); } /*! @@ -4199,14 +4215,14 @@ class basic_json { if (idx >= size()) { - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); } m_value.array->erase(m_value.array->begin() + static_cast(idx)); } else { - throw std::domain_error("cannot use erase() with " + type_name()); + JSON_THROW(std::domain_error("cannot use erase() with " + type_name())); } } @@ -4924,7 +4940,7 @@ class basic_json // push_back only works for null objects or arrays if (not(is_null() or is_array())) { - throw std::domain_error("cannot use push_back() with " + type_name()); + JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); } // transform null object into an array @@ -4960,7 +4976,7 @@ class basic_json // push_back only works for null objects or arrays if (not(is_null() or is_array())) { - throw std::domain_error("cannot use push_back() with " + type_name()); + JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); } // transform null object into an array @@ -5010,7 +5026,7 @@ class basic_json // push_back only works for null objects or objects if (not(is_null() or is_object())) { - throw std::domain_error("cannot use push_back() with " + type_name()); + JSON_THROW(std::domain_error("cannot use push_back() with " + type_name())); } // transform null object into an object @@ -5110,7 +5126,7 @@ class basic_json // emplace_back only works for null objects or arrays if (not(is_null() or is_array())) { - throw std::domain_error("cannot use emplace_back() with " + type_name()); + JSON_THROW(std::domain_error("cannot use emplace_back() with " + type_name())); } // transform null object into an array @@ -5158,7 +5174,7 @@ class basic_json // emplace only works for null objects or arrays if (not(is_null() or is_object())) { - throw std::domain_error("cannot use emplace() with " + type_name()); + JSON_THROW(std::domain_error("cannot use emplace() with " + type_name())); } // transform null object into an object @@ -5209,7 +5225,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } // insert to array and return iterator @@ -5218,7 +5234,7 @@ class basic_json return result; } - throw std::domain_error("cannot use insert() with " + type_name()); + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); } /*! @@ -5262,7 +5278,7 @@ class basic_json // check if iterator pos fits to this JSON value if (pos.m_object != this) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } // insert to array and return iterator @@ -5271,7 +5287,7 @@ class basic_json return result; } - throw std::domain_error("cannot use insert() with " + type_name()); + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); } /*! @@ -5309,24 +5325,24 @@ class basic_json // insert only works for arrays if (not is_array()) { - throw std::domain_error("cannot use insert() with " + type_name()); + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); } // check if iterator pos fits to this JSON value if (pos.m_object != this) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } // check if range iterators belong to the same JSON object if (first.m_object != last.m_object) { - throw std::domain_error("iterators do not fit"); + JSON_THROW(std::domain_error("iterators do not fit")); } if (first.m_object == this or last.m_object == this) { - throw std::domain_error("passed iterators may not belong to container"); + JSON_THROW(std::domain_error("passed iterators may not belong to container")); } // insert to array and return iterator @@ -5367,13 +5383,13 @@ class basic_json // insert only works for arrays if (not is_array()) { - throw std::domain_error("cannot use insert() with " + type_name()); + JSON_THROW(std::domain_error("cannot use insert() with " + type_name())); } // check if iterator pos fits to this JSON value if (pos.m_object != this) { - throw std::domain_error("iterator does not fit current value"); + JSON_THROW(std::domain_error("iterator does not fit current value")); } // insert to array and return iterator @@ -5440,7 +5456,7 @@ class basic_json } else { - throw std::domain_error("cannot use swap() with " + type_name()); + JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); } } @@ -5473,7 +5489,7 @@ class basic_json } else { - throw std::domain_error("cannot use swap() with " + type_name()); + JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); } } @@ -5506,7 +5522,7 @@ class basic_json } else { - throw std::domain_error("cannot use swap() with " + type_name()); + JSON_THROW(std::domain_error("cannot use swap() with " + type_name())); } } @@ -6350,7 +6366,7 @@ class basic_json { if (current_index + sizeof(T) + 1 > vec.size()) { - throw std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector"); + JSON_THROW(std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector")); } T result; @@ -6900,19 +6916,19 @@ class basic_json // simple case: requested length is greater than the vector's length if (len > size or offset > size) { - throw std::out_of_range("len out of range"); + JSON_THROW(std::out_of_range("len out of range")); } // second case: adding offset would result in overflow if ((size > (std::numeric_limits::max() - offset))) { - throw std::out_of_range("len+offset out of range"); + JSON_THROW(std::out_of_range("len+offset out of range")); } // last case: reading past the end of the vector if (len + offset > size) { - throw std::out_of_range("len+offset out of range"); + JSON_THROW(std::out_of_range("len+offset out of range")); } } @@ -7148,7 +7164,7 @@ class basic_json default: { - throw std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx]))); + JSON_THROW(std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); } } } @@ -7631,7 +7647,7 @@ class basic_json default: // anything else (0xFF is handled inside the other types) { - throw std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx]))); + JSON_THROW(std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast(v[current_idx])))); } } } @@ -8521,7 +8537,7 @@ class basic_json case basic_json::value_t::null: { - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } default: @@ -8531,7 +8547,7 @@ class basic_json return *m_object; } - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } } } @@ -8565,7 +8581,7 @@ class basic_json return m_object; } - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } } } @@ -8665,7 +8681,7 @@ class basic_json // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { - throw std::domain_error("cannot compare iterators of different containers"); + JSON_THROW(std::domain_error("cannot compare iterators of different containers")); } assert(m_object != nullptr); @@ -8707,7 +8723,7 @@ class basic_json // if objects are not the same, the comparison is undefined if (m_object != other.m_object) { - throw std::domain_error("cannot compare iterators of different containers"); + JSON_THROW(std::domain_error("cannot compare iterators of different containers")); } assert(m_object != nullptr); @@ -8716,7 +8732,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot compare order of object iterators"); + JSON_THROW(std::domain_error("cannot compare order of object iterators")); } case basic_json::value_t::array: @@ -8770,7 +8786,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use offsets with object iterators"); + JSON_THROW(std::domain_error("cannot use offsets with object iterators")); } case basic_json::value_t::array: @@ -8832,7 +8848,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use offsets with object iterators"); + JSON_THROW(std::domain_error("cannot use offsets with object iterators")); } case basic_json::value_t::array: @@ -8859,7 +8875,7 @@ class basic_json { case basic_json::value_t::object: { - throw std::domain_error("cannot use operator[] for object iterators"); + JSON_THROW(std::domain_error("cannot use operator[] for object iterators")); } case basic_json::value_t::array: @@ -8869,7 +8885,7 @@ class basic_json case basic_json::value_t::null: { - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } default: @@ -8879,7 +8895,7 @@ class basic_json return *m_object; } - throw std::out_of_range("cannot get value"); + JSON_THROW(std::out_of_range("cannot get value")); } } } @@ -8897,7 +8913,7 @@ class basic_json return m_it.object_iterator->first; } - throw std::domain_error("cannot use key() for non-object iterators"); + JSON_THROW(std::domain_error("cannot use key() for non-object iterators")); } /*! @@ -9082,7 +9098,7 @@ class basic_json // immediately abort if stream is erroneous if (s.fail()) { - throw std::invalid_argument("stream error"); + JSON_THROW(std::invalid_argument("stream error")); } // fill buffer @@ -9149,7 +9165,7 @@ class basic_json } else { - throw std::invalid_argument("missing or wrong low surrogate"); + JSON_THROW(std::invalid_argument("missing or wrong low surrogate")); } } @@ -9183,7 +9199,7 @@ class basic_json } else { - throw std::out_of_range("code points above 0x10FFFF are invalid"); + JSON_THROW(std::out_of_range("code points above 0x10FFFF are invalid")); } return result; @@ -9565,7 +9581,7 @@ class basic_json // make sure there is a subsequent unicode if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') { - throw std::invalid_argument("missing low surrogate"); + JSON_THROW(std::invalid_argument("missing low surrogate")); } // get code yyyy from uxxxx\uyyyy @@ -9578,7 +9594,7 @@ class basic_json else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF) { // we found a lone low surrogate - throw std::invalid_argument("missing high surrogate"); + JSON_THROW(std::invalid_argument("missing high surrogate")); } else { @@ -10056,7 +10072,7 @@ class basic_json "'") : lexer::token_type_name(last_token)); error_msg += "; expected " + lexer::token_type_name(t); - throw std::invalid_argument(error_msg); + JSON_THROW(std::invalid_argument(error_msg)); } } @@ -10068,7 +10084,7 @@ class basic_json error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + "'") : lexer::token_type_name(last_token)); - throw std::invalid_argument(error_msg); + JSON_THROW(std::invalid_argument(error_msg)); } } @@ -10164,7 +10180,7 @@ class basic_json { if (is_root()) { - throw std::domain_error("JSON pointer has no parent"); + JSON_THROW(std::domain_error("JSON pointer has no parent")); } auto last = reference_tokens.back(); @@ -10182,7 +10198,7 @@ class basic_json { if (is_root()) { - throw std::domain_error("JSON pointer has no parent"); + JSON_THROW(std::domain_error("JSON pointer has no parent")); } json_pointer result = *this; @@ -10243,7 +10259,7 @@ class basic_json */ default: { - throw std::domain_error("invalid value to unflatten"); + JSON_THROW(std::domain_error("invalid value to unflatten")); } } } @@ -10311,7 +10327,7 @@ class basic_json // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - throw std::domain_error("array index must not begin with '0'"); + JSON_THROW(std::domain_error("array index must not begin with '0'")); } if (reference_token == "-") @@ -10329,7 +10345,7 @@ class basic_json default: { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); } } } @@ -10363,7 +10379,7 @@ class basic_json // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - throw std::domain_error("array index must not begin with '0'"); + JSON_THROW(std::domain_error("array index must not begin with '0'")); } // note: at performs range check @@ -10373,7 +10389,7 @@ class basic_json default: { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); } } } @@ -10415,7 +10431,7 @@ class basic_json // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - throw std::domain_error("array index must not begin with '0'"); + JSON_THROW(std::domain_error("array index must not begin with '0'")); } // use unchecked array access @@ -10425,7 +10441,7 @@ class basic_json default: { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); } } } @@ -10459,7 +10475,7 @@ class basic_json // error condition (cf. RFC 6901, Sect. 4) if (reference_token.size() > 1 and reference_token[0] == '0') { - throw std::domain_error("array index must not begin with '0'"); + JSON_THROW(std::domain_error("array index must not begin with '0'")); } // note: at performs range check @@ -10469,7 +10485,7 @@ class basic_json default: { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + JSON_THROW(std::out_of_range("unresolved reference token '" + reference_token + "'")); } } } @@ -10491,7 +10507,7 @@ class basic_json // check if nonempty reference string begins with slash if (reference_string[0] != '/') { - throw std::domain_error("JSON pointer must be empty or begin with '/'"); + JSON_THROW(std::domain_error("JSON pointer must be empty or begin with '/'")); } // extract the reference tokens: @@ -10526,7 +10542,7 @@ class basic_json (reference_token[pos + 1] != '0' and reference_token[pos + 1] != '1')) { - throw std::domain_error("escape error: '~' must be followed with '0' or '1'"); + JSON_THROW(std::domain_error("escape error: '~' must be followed with '0' or '1'")); } } @@ -10652,7 +10668,7 @@ class basic_json { if (not value.is_object()) { - throw std::domain_error("only objects can be unflattened"); + JSON_THROW(std::domain_error("only objects can be unflattened")); } basic_json result; @@ -10662,7 +10678,7 @@ class basic_json { if (not element.second.is_primitive()) { - throw std::domain_error("values in object must be primitive"); + JSON_THROW(std::domain_error("values in object must be primitive")); } // assign value to reference pointed to by JSON pointer; Note @@ -10991,7 +11007,7 @@ class basic_json if (static_cast(idx) > parent.size()) { // avoid undefined behavior - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + JSON_THROW(std::out_of_range("array index " + std::to_string(idx) + " is out of range")); } else { @@ -11029,7 +11045,7 @@ class basic_json } else { - throw std::out_of_range("key '" + last_path + "' not found"); + JSON_THROW(std::out_of_range("key '" + last_path + "' not found")); } } else if (parent.is_array()) @@ -11043,7 +11059,7 @@ class basic_json if (not json_patch.is_array()) { // a JSON patch must be an array of objects - throw std::invalid_argument("JSON patch must be an array of objects"); + JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); } // iterate and apply th eoperations @@ -11063,13 +11079,13 @@ class basic_json // check if desired value is present if (it == val.m_value.object->end()) { - throw std::invalid_argument(error_msg + " must have member '" + member + "'"); + JSON_THROW(std::invalid_argument(error_msg + " must have member '" + member + "'")); } // check if result is of type string if (string_type and not it->second.is_string()) { - throw std::invalid_argument(error_msg + " must have string member '" + member + "'"); + JSON_THROW(std::invalid_argument(error_msg + " must have string member '" + member + "'")); } // no error: return value @@ -11079,7 +11095,7 @@ class basic_json // type check if (not val.is_object()) { - throw std::invalid_argument("JSON patch must be an array of objects"); + JSON_THROW(std::invalid_argument("JSON patch must be an array of objects")); } // collect mandatory members @@ -11138,13 +11154,13 @@ class basic_json case patch_operations::test: { bool success = false; - try + JSON_TRY { // check if "value" matches the one at "path" // the "path" location must exist - use at() success = (result.at(ptr) == get_value("test", "value", false)); } - catch (std::out_of_range&) + JSON_CATCH (std::out_of_range&) { // ignore out of range errors: success remains false } @@ -11152,7 +11168,7 @@ class basic_json // throw an exception if test fails if (not success) { - throw std::domain_error("unsuccessful: " + val.dump()); + JSON_THROW(std::domain_error("unsuccessful: " + val.dump())); } break; @@ -11162,7 +11178,7 @@ class basic_json { // op must be "add", "remove", "replace", "move", "copy", or // "test" - throw std::invalid_argument("operation value '" + op + "' is invalid"); + JSON_THROW(std::invalid_argument("operation value '" + op + "' is invalid")); } } } @@ -11435,4 +11451,10 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #pragma GCC diagnostic pop #endif +// clean up +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_CATCH +#undef JSON_DEPRECATED + #endif diff --git a/test/Makefile b/test/Makefile index 3d5595d21..0b235ba19 100644 --- a/test/Makefile +++ b/test/Makefile @@ -75,7 +75,7 @@ test-%: src/unit-%.cpp ../src/json.hpp thirdparty/catch/catch.hpp @echo "[CXXLD] $@" @$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) -DCATCH_CONFIG_MAIN $< -o $@ -TEST_PATTERN = "*" +TEST_PATTERN ?= "*" TEST_PREFIX = "" check: $(TESTCASES) @cd .. ; for testcase in $(TESTCASES); do echo "Executing $$testcase..."; $(TEST_PREFIX)test/$$testcase $(TEST_PATTERN) || exit 1; done diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 92238b79f..43f9f4338 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1187,7 +1187,7 @@ TEST_CASE("single CBOR roundtrip") } } -TEST_CASE("CBOR regressions") +TEST_CASE("CBOR regressions", "[!throws]") { SECTION("fuzz test results") { diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 1ba6aa613..f12da1e43 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -298,25 +298,6 @@ TEST_CASE("element access 2") CHECK(j_const.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3})); } - SECTION("access non-existing value") - { - CHECK(j.value("/not/existing"_json_pointer, 2) == 2); - CHECK(j.value("/not/existing"_json_pointer, 2u) == 2u); - CHECK(j.value("/not/existing"_json_pointer, false) == false); - CHECK(j.value("/not/existing"_json_pointer, "bar") == "bar"); - CHECK(j.value("/not/existing"_json_pointer, 12.34) == Approx(12.34)); - CHECK(j.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}})); - CHECK(j.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100})); - - CHECK(j_const.value("/not/existing"_json_pointer, 2) == 2); - CHECK(j_const.value("/not/existing"_json_pointer, 2u) == 2u); - CHECK(j_const.value("/not/existing"_json_pointer, false) == false); - CHECK(j_const.value("/not/existing"_json_pointer, "bar") == "bar"); - CHECK(j_const.value("/not/existing"_json_pointer, 12.34) == Approx(12.34)); - CHECK(j_const.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}})); - CHECK(j_const.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100})); - } - SECTION("access on non-object type") { SECTION("null") @@ -957,3 +938,37 @@ TEST_CASE("element access 2") } } } + +TEST_CASE("element access 2 (throwing tests)", "[!throws]") +{ + SECTION("object") + { + json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}}; + const json j_const = j; + + SECTION("access specified element with default value") + { + SECTION("given a JSON pointer") + { + SECTION("access non-existing value") + { + CHECK(j.value("/not/existing"_json_pointer, 2) == 2); + CHECK(j.value("/not/existing"_json_pointer, 2u) == 2u); + CHECK(j.value("/not/existing"_json_pointer, false) == false); + CHECK(j.value("/not/existing"_json_pointer, "bar") == "bar"); + CHECK(j.value("/not/existing"_json_pointer, 12.34) == Approx(12.34)); + CHECK(j.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}})); + CHECK(j.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100})); + + CHECK(j_const.value("/not/existing"_json_pointer, 2) == 2); + CHECK(j_const.value("/not/existing"_json_pointer, 2u) == 2u); + CHECK(j_const.value("/not/existing"_json_pointer, false) == false); + CHECK(j_const.value("/not/existing"_json_pointer, "bar") == "bar"); + CHECK(j_const.value("/not/existing"_json_pointer, 12.34) == Approx(12.34)); + CHECK(j_const.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}})); + CHECK(j_const.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100})); + } + } + } + } +} From a00149f8ee60a48fe7735d3eecd209b509e2168f Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 16 Jan 2017 22:36:58 +0100 Subject: [PATCH 2/3] :bug: fixed logic error --- .travis.yml | 4 ++-- src/json.hpp | 10 +++++----- src/json.hpp.re2c | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a154deb7..fc7e5db0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -78,13 +78,13 @@ matrix: env: - COMPILER=g++-4.9 - SPECIAL=no_exceptions - - TEST_PATTERN="-e \"*\"" + - TEST_PATTERN=-e "*" addons: apt: sources: ['ubuntu-toolchain-r-test'] packages: [g++-4.9, cppcheck] before_script: - - make FLAGS="-fno-exceptions" + - CPPFLAGS="-DJSON_NOEXCEPTION" make # Coveralls (http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/) diff --git a/src/json.hpp b/src/json.hpp index 69d49ec17..fa9b85f26 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -89,14 +89,14 @@ SOFTWARE. #endif // allow to disable exceptions -#if defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) -#else +#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) #endif /*! diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 31accc98f..886b9dde5 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -89,14 +89,14 @@ SOFTWARE. #endif // allow to disable exceptions -#if defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) -#else +#if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) #endif /*! From 87c5e32e1faf7f54a3f6241c288aa0c1a39c4a3f Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 16 Jan 2017 22:46:49 +0100 Subject: [PATCH 3/3] :bug: fixed escaping --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fc7e5db0c..ef5c6143f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -78,7 +78,7 @@ matrix: env: - COMPILER=g++-4.9 - SPECIAL=no_exceptions - - TEST_PATTERN=-e "*" + - TEST_PATTERN=-e \"*\" addons: apt: sources: ['ubuntu-toolchain-r-test']